Fazendo um resumo das sentenças [duplicado]

7

Eu tenho dados e quero resumir frases para gerar conclusões. O exemplo abaixo não está relacionado aos dados, mas apenas para esclarecer a ideia para que eu possa replicá-la.

Employee Suzie signed one time.
Employee Dan signed one time.
Employee Jordan signed one time.
Employee Suzie signed one time.
Employee Suzie signed one time.
Employee Harold signed one time.
Employee Sebastian signed one time.
Employee Jordan signed one time.
Employee Suzie signed one time.
Employee Suzan signed one time.

Eu quero fazer um resumo dessas frases, assim:

Jordan signed 2 time(s)
Dan signed 1 time(s)
Suzie signed 4 time(s)
Suzan signed 1 time(s)
Sebastian signed 1 time(s)
Harold signed 1 time(s)

Eu joguei com awk , mas parece muito difícil fazê-lo. Então eu tentei sed , mas não funcionou. Parece que sed é apenas para encontrar e alterar coisas.

    
por Peter Mortensen 18.10.2018 / 13:59

5 respostas

14

A abordagem geral seria

$ awk '{ count[$2]++ }
       END {
           for (name in count)
               printf("%s signed %d time(s)\n", name, count[name])
       }' <file
Harold signed 1 time(s)
Dan signed 1 time(s)
Sebastian signed 1 time(s)
Suzie signed 4 time(s)
Jordan signed 2 time(s)
Suzan signed 1 time(s)

Ou seja, use um array / hash associativo para armazenar o número de vezes que um determinado nome é visto. No bloco END , repita todos os nomes e imprima o resumo de cada um.

Para uma formatação um pouco mais agradável, altere o espaço reservado %s na chamada printf() para algo como %-10s para reservar 10 caracteres para os nomes (justificados à esquerda).

$ awk '{ count[$2]++ }
       END {
           for (name in count)
               printf("%-10s signed %d time(s)\n", name, count[name])
       }' <file
Harold     signed 1 time(s)
Dan        signed 1 time(s)
Sebastian  signed 1 time(s)
Suzie      signed 4 time(s)
Jordan     signed 2 time(s)
Suzan      signed 1 time(s)

Mais brincando com a saída (porque estou entediado):

$ awk '{ count[$2]++ }
       END {
           for (name in count)
               printf("%-10s signed %d time%s\n", name, count[name],
                      count[name] > 1 ? "s" : "" )
       }' <file
Harold     signed 1 time
Dan        signed 1 time
Sebastian  signed 1 time
Suzie      signed 4 times
Jordan     signed 2 times
Suzan      signed 1 time
    
por 18.10.2018 / 14:06
8

Enquanto awk está usando uma matriz associada e isso seria limitado ao tamanho da memória que você tem, você pode fazer o seguinte:

sort -k2,2 infile | uniq -c

Ou para fazer a formatação que você quiser:

sort -k2,2 infile  |uniq -c |awk '{ print $3, "signed", $1, "time(s)" }'
    
por 18.10.2018 / 14:19
3

Este trabalho é para awk . Você precisa de um array[index] para fazer isso:

awk 'NF {name[$2]++} END{for (each in name) {print each " signed " name[each] " time(s)"}}' file

Jordan signed 2 time(s)
Dan signed 1 time(s)
Suzie signed 4 time(s)
Suzan signed 1 time(s)
Sebastian signed 1 time(s)
Harold signed 1 time(s)

NF é remover linhas em branco extras. Os dados são armazenados no índice e no valor da matriz. Os valores são referenciados com o índice correspondente.

    
por 18.10.2018 / 14:05
0

Sem formatação, a solução mais simples é

sort|uniq -c

uniq -c conta as linhas e os prefixam com sua contagem, o tipo é necessário para que o uniq funcione.

$ sort|uniq -c
asdf
asdf
qwer
[ctrl-d]
      2 asdf
      1 qwer

Sua formatação pode ser obtida por sed ou awk, se você precisar do formato exato:

awk '{print $2}'|sort|uniq -c|awk '{print($2, "signed" ,$1, "time(s)")}'
    
por 18.10.2018 / 15:02
-1

Eu tentei uma solução 'for', embora eu tenha certeza de que isso pode ser reeditado e tornar-se dandy. Serve o propósito embora.

for name in $(awk '{print $2}' x.txt)
do
count=$(grep -i $i x.txt|wc -l)
echo "$i signed in $count times" >>xy.txt
done

sort -u xy.txt

Dan signed in 3 times
Harold signed in 1 times
Jordan signed in 2 times
Sebastian signed in 1 times
Suzan signed in 1 times
Suzie signed in 4 times
    
por 18.10.2018 / 19:46