Eu queria ver se isso poderia ser resolvido usando um one-liner Perl, que consegui descobrir:
$ perl -F, -ane '$lcnt{$F[0]}++; $ccnt{$F[0]}{$F[1]}++; \
END { print "$_, $lcnt{$_}, " . (keys %{ $ccnt{$_} }) . "\n" for sort keys %lcnt }' \
file
A, 3, 2
B, 2, 2
C, 2, 1
D, 1, 1
Divisão
loop em um arquivo
Este one-liner pode parecer muito complicado, mas na verdade é bem simples quando você o divide. No coração disso está esse mecanismo em Perl:
$ perl -F, -ane '...; END { ... }' file
Isso diz ao Perl para pegar o arquivo file
em e fazer um loop sobre ele e dividi-lo automaticamente usando -F,
como o caractere separador, quando completo, execute o bloco END {..}
uma vez e saia.
Por exemplo:
$ perl -F, -ane 'print "arg1: $F[0] arg2: $F[1]"; END { print "DONE\n" }' file
arg1: A arg2: 10
arg1: B arg2: 11
arg1: C arg2: 12
arg1: A arg2: 10
arg1: B arg2: 12
arg1: D arg2: 10
arg1: A arg2: 12
arg1: C arg2: 12
DONE
NOTA: o recurso de divisão automática do Perl coloca automaticamente as colunas em uma matriz @F
, aqui estou usando os elementos 1 & 2, $F[0]
& $F[1]
.
Contando as coisas
A próxima coisa que precisamos fazer é contar vários bits da entrada. Para isso, vamos contar com o poder dos hashes em Perl. Nós vamos usar 2, %lcnt
e %ccnt
.
NOTA: Uma das coisas mais irritantes com o Perl é a mudança de notação ao definir um hash versus acessá-lo. Quando nós o acessamos, nós mudamos de %lcnt
para $lcnt["A"]
, mas eu divago.
$lcnt{$F[0]}++; $ccnt{$F[0]}{$F[1]}++;
-
%lcnt
- contagem de caracteres da primeira coluna
-
%ccnt
- hash bidimensional contendo 2 coordenadas para acessar uma contagem da segunda coluna
NOTA: A contagem de coisas dessa maneira permite que a função exclusiva seja executada simplesmente pela maneira como estamos contando os bits.
Por exemplo, vamos examinar o conteúdo do %lcnt
hash:
$ perl -F, -ane '$lcnt{$F[0]}++; $ccnt{$F[0]}{$F[1]}++; \
END { print "key: $_\n" for sort keys %lcnt }' file
key: A
key: B
key: C
key: D
Se quisermos ver o valor de cada hash:
$ perl -F, -ane '$lcnt{$F[0]}++; $ccnt{$F[0]}{$F[1]}++; \
END { print "key: $_ val: $lcnt{$_}\n" for sort keys %lcnt }' file
key: A val: 3
key: B val: 2
key: C val: 2
key: D val: 1
OBSERVAÇÃO: Aqui podemos ver que o $lcnt{$F[0]}++
fez todo o trabalho duro de contar cada caractere enquanto passamos pelo arquivo e os adicionamos a o hash %lcnt
.
Este é o END
A última peça do quebra-cabeça é exibir todas as informações coletadas de uma maneira útil. Para isso, vamos usar isso no END {...}
:
print "$_, $lcnt{$_}, " . (keys %{ $ccnt{$_} }) . "\n" for sort keys %lcnt
Isso percorre a lista de chaves de %lcnt
e imprime a seguinte linha:
$_, $lcnt{$_}, " . (keys %{ $ccnt{$_} }) . "\n"
Se é difícil ver a estrutura acima, aqui é mais geral:
A, 3, 2
^--- (keys %{ $ccnt{$_} }) ## count of unique columns for each character ($_)
^------ $lcnt{$_} ## count of each character
^--------- $_ ## character
Isso produzirá uma linha que contém o caractere ( $_
), o valor da contagem para esse caractere ( $lcnt{$_}
) e a contagem de valores exclusivos da segunda coluna para cada caractere.
Referências