GRUPO POR + COUNT sobre linhas em uma região

7

Qual é a maneira mais simples de obter o número de repetições distintas em uma região?

Por exemplo, de

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

Eu gostaria de receber

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

A saída pode ser feita na mesma região (substituindo a seleção atual).

rsenna
fonte

Respostas:

10

No Linux, e suponho que Mac, você pode canalizar a região através do uniqcomando shell para obter quase exatamente o que deseja.

  1. Marque a região

  2. Classifique as linhas com M-x sort-lines

  3. Ligue shell-command-on-regioncom a tecla prefixo:C-u M-|

  4. Entrar uniq --count

O conteúdo do buffer será substituído por:

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

Você pode automatizar ainda mais isso com macros de teclado etc., mas isso pode ser bom o suficiente como está.

EDIT: como aponta @phils, você pode fazer a classificação com um comando shell em vez de com a função Emacs. Nesse caso, solte a etapa 2 e, na etapa 4, insira em sort | uniq -cvez de apenas uniq -c.

Tyler
fonte
Agradável! Em um Mac, você uniqtem a -copção de acrescentar contagens, e não acho que você precise classificá-las antes de usar uniq. (Além disso, a OP pediu processar a região , e não todo o tampão.)
Constantino
Obrigado. No Linux -ce --countsão sinônimos, é necessário classificar, mas talvez a versão para Mac use padrões diferentes. Vou corrigir o passo 1!
Tyler
Eu acabei sshde entrar em uma caixa Ubuntu 14.04.1 LTS: ainda não há classificação necessária para mim.
Constantine
11
Tyler:C-u M-| sort | uniq -c
phils
11
Ugh. Estou muito lento para editar comentários. Aqui está o que eu pretendia dizer: "@rsenna: Foi você quem fez a pergunta; feliz em saber que funcionou para você. (Eu não me importo com pontos de reputação; eu aprecio um +1, mas concordo absolutamente que minha resposta não dá o "caminho mais simples".) "
Constantine
5

Eu vejo três tarefas aqui:

  1. Obtenha uma lista de linhas em uma região, sem duplicatas.
  2. Para cada linha nesta lista, conte quantas vezes ocorreu na região original e colete essas informações.
  3. Inserir o resumo.

 

(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)))
Constantine
fonte
Eu não sabia how-manyou delete-duplicate-linesexistia - às vezes parece que você pode simplesmente juntar palavras em inglês com hífens e o Emacs sabe o que fazer! Suspeito que também haja uma versão interna do Emacs uniq, mas não a encontrei.
Tyler
2
Esta é uma resposta muito boa. E, como não depende de nenhum comando externo, também funciona no Windows.
rsenna