GROUP BY + COUNT über Linien in einer Region

7

Was ist der einfachste Weg, um die Anzahl der in einer Region wiederholten Unterscheidungsmerkmale zu ermitteln?

Zum Beispiel von

THIS IS LINE A
THIS IS LINE A
THIS IS LINE A
THIS IS LINE B
THIS IS LINE B
THIS IS LINE C

Ich hätte gern

THIS IS LINE A    3
THIS IS LINE B    2
THIS IS LINE C    1

Die Ausgabe könnte über dieselbe Region erfolgen (anstelle der aktuellen Auswahl).

rsenna
quelle

Antworten:

10

Unter Linux und vermutlich unter Mac können Sie die Region über den uniqShell-Befehl leiten, um fast genau das zu erhalten, was Sie möchten.

  1. Markieren Sie die Region

  2. Sortieren Sie die Zeilen mit M-x sort-lines

  3. Rufen Sie shell-command-on-regionmit der Präfix-Taste an:C-u M-|

  4. Eingeben uniq --count

Der Inhalt des Puffers wird ersetzt durch:

  3 THIS IS LINE A
  2 THIS IS LINE B
  1 THIS IS LINE C

Sie können dies mit Tastaturmakros usw. weiter automatisieren, dies kann jedoch so wie es ist gut genug sein.

BEARBEITEN: Wie @phils hervorhebt, können Sie die Sortierung mit einem Shell-Befehl anstatt mit der Emacs-Funktion durchführen. Lassen Sie in diesem Fall Schritt 2 fallen und geben Sie für Schritt 4 sort | uniq -cstatt nur ein uniq -c.

Tyler
quelle
Nett! Auf einem Mac besteht uniqdie -cMöglichkeit, Zählungen voranzustellen, und ich glaube nicht, dass Sie vor der Verwendung sortieren müssen uniq. (Auch das OP fragte die Verarbeitung der Region , nicht des gesamten Puffers.)
Constantine
Vielen Dank. Unter Linux -cund --countsind Synonyme, und Sie müssen sortieren, aber möglicherweise verwendet die Mac-Version andere Standardeinstellungen. Ich werde Schritt 1 korrigieren!
Tyler
Ich war gerade sshin einer Kiste, die lief Ubuntu 14.04.1 LTS: Ich brauchte immer noch keine Sortierung.
Konstantin
1
Tyler:C-u M-| sort | uniq -c
Phils
1
Pfui. Ich bin zu langsam, um Kommentare zu bearbeiten. Folgendes wollte ich sagen: "@rsenna: Du bist derjenige, der die Frage gestellt hat; ich bin froh zu wissen, dass es für dich funktioniert hat. (Ich interessiere mich nicht für Reputationspunkte; ich schätze eine +1, aber ich stimme absolut zu dass meine Antwort nicht den "einfachsten Weg" gibt.) "
Konstantin
5

Ich sehe hier drei Aufgaben:

  1. Holen Sie sich eine Liste der Zeilen in einer Region ohne Duplikate.
  2. Zählen Sie für jede Zeile in dieser Liste, wie oft sie in der ursprünglichen Region aufgetreten ist, und sammeln Sie diese Informationen.
  3. Fügen Sie die Zusammenfassung ein.

 

(defun uniqify-lines (beg end)
  "Return a list of lines in a region (without duplicates). Omit empty lines."
  (let ((text (buffer-substring beg end)))
    (with-temp-buffer
      (insert text)
      (delete-duplicate-lines (point-min) (point-max))
      (split-string (buffer-string) "\n" t))))

(defun count-duplicates (beg end)
  "Count duplicate lines in a region. Returns a list of the
    form ((line . count) ...)."
  (mapcar (lambda (str)
            (cons str (how-many (regexp-quote str) beg end)))
          (uniqify-lines beg end)))

(defun insert-line-stats (beg end)
  "Remove duplicate lines in the region. Append the number of
    occurences to each line in the result. Replaces current region."
  (interactive "r")
  (let ((stats (count-duplicates beg end)))
    (kill-region beg end)
    (mapc (lambda (line)
            (insert (format "%s %d\n" (car line) (cdr line))))
          stats)))
Konstantin
quelle
Ich wusste es nicht how-manyoder delete-duplicate-linesexistierte nicht - manchmal scheint es, als könne man englische Wörter einfach mit Bindestrichen verbinden und Emacs weiß, was zu tun ist! Ich vermute, es gibt auch eine integrierte Emacs-Version von uniq, aber ich habe sie nicht gefunden.
Tyler
2
Dies ist eine sehr gute Antwort. Und da es nicht von einem externen Befehl abhängt, funktioniert es auch unter Windows.
Rsenna