Que tal
cut -d. -f1 numbers.txt | sort | uniq -c
Usando seus dados de exemplo,
$ cut -d. -f1 numbers.txt | sort | uniq -c
3 24
4 25
1 26
1 29
3 30
Eu tenho um arquivo com números no formato float.
Posso revisá-los via sort -rn numbers.txt | less
Eu gostaria de poder "agrupá-los". Ou seja veja facilmente quantos estão no mesmo intervalo.
Para dar um exemplo do arquivo:
30.9695041179657
30.8851490020752
30.2127060890198
29.1361880302429
26.4587681293488
25.8535399436951
25.7361891269684
25.7305450439453
25.1068568229675
24.7598769664764
24.3106801509857
24.0782940387726
Eu não me importo com precisão. Então eu gostaria de saber quantos 25's estão no arquivo, por exemplo neste caso, 4 e 30, etc, para todos os números no arquivo.
Portanto, para este exemplo, uma saída como: 3 para 30, 1 para 29, 1 para 26, 4 para 25, 3 para 24.
Existe uma maneira fácil de fazer isso?
Que tal
cut -d. -f1 numbers.txt | sort | uniq -c
Usando seus dados de exemplo,
$ cut -d. -f1 numbers.txt | sort | uniq -c
3 24
4 25
1 26
1 29
3 30
com awk
( mawk
):
$ awk -F . '{COUNTS[$1]++} END{for(ct in COUNTS) {printf("%d %d time(s)\n", ct, COUNTS[ct])}}' test.txt
30 3 time(s)
24 3 time(s)
25 4 time(s)
26 1 time(s)
29 1 time(s)
O -F
define o separador de campo ( FS
) como .
, além de percorrer todas as linhas com {COUNTS[$1]++}
, usando $1
como a parte antes do separador decimal ( .
) e manter um registro de quantas vezes os encontramos em uma matriz chamada COUNTS
.
No final ( END {}
), despejamos o que encontramos. Como você pode ver, a maior parte é a saída.
Um pouco mais legível em um arquivo:
{COUNTS[$1]++}
END {
for(ct in COUNTS)
{
printf("%d %d time(s)\n", ct, COUNTS[ct])
}
}
Você pode usar awk
:
awk '{a[int($1)]++}END{for (i in a) {print a[i], i}}' inputfile
Se você quiser que a saída seja classificada, canalize a saída para sort
:
awk '{a[int($1)]++}END{for (i in a) {print a[i], i}}' inputfile | sort -k2
Para sua entrada de amostra, isso produziria:
3 24
4 25
1 26
1 29
3 30
Em perl
:
perl -lan -F'\.' -e '$count{$F[0]}++;
END{
print "$_ --> $count{$_}" for sort {$a <=> $b} keys %count
}' your_file
Editar
Provavelmente mais eficiente:
perl -ne '
$count{int()}++;
END{ print "$_ --> $count{$_}" for sort {$a <=> $b} keys %count }'
your_file
cut -b-2 numbers.txt | sort -n | uniq -c | sort -nr
cut -b-2
seleciona os dois primeiros caracteres, sort -nr
classifica os resultados pela maior frequência primeiro
Resultado resultante:
4 25
3 30
3 24
1 29
1 26
Ou como um oneliner python, só para o inferno:
python -c 'l = [x[:2] for x in open("numbers.txt").readlines()];print(list(reversed(sorted([(l.count(x),x) for x in set(l)]))))'
Resultado resultante:
[(4, '25'), (3, '30'), (3, '24'), (1, '29'), (1, '26')]
Parece que seu arquivo foi classificado, então você pode fazer assim:
$ uniq -c <(perl -pe 's/\.\d*//' file)
3 30
1 29
1 26
4 25
3 24
Se não tiver sido ordenado:
$ uniq -c <(perl -pe 's/\.\d*//' file | sort -rn)
3 30
1 29
1 26
4 25
3 24
$ grep -oP '^\d+' file | sort | uniq -c
3 24
4 25
1 26
1 29
3 30
O -o
sinalizador diz grep
para imprimir apenas a parte correspondente da linha e o -P
ativa Perl Compatible Regular Expressions que nos permite usar \d
para números. Assim, o grep
imprimirá o maior número de dígitos encontrados no início da linha (ou seja, até o primeiro não dígito, o .
) e, em seguida, sort
classificará a saída e uniq -c
contará o número. número de ocorrências de cada string na entrada.
$ perl -lne '/^\d+/ && $k{$&}++; END{print "$k{$_} : $_" for sort keys %k}' file
3 : 24
4 : 25
1 : 26
1 : 29
3 : 30
O $&
é a string correspondida na operação de correspondência anterior, portanto, armazenamos em um hash ( %k
) e incrementamos seu valor em um. O bloco END
imprimirá cada número encontrado ( $_
) e o valor que tiver no hash ( $k{$_}
), o número de vezes que foi encontrado.
$ while IFS='\.' read -r a b; do (( ll[$a]++ )); done < file;
for i in ${!ll[@]} ; do echo ${ll[$i]} : $i; done
3 : 24
4 : 25
1 : 26
1 : 29
3 : 30
IFS
definido como .
significa que as linhas de entrada são divididas em registros em .
, de modo que $a
serão os primeiros dígitos até .
. Nós os iteramos e os usamos como chaves para um array associativo cujo valor é aumentado toda vez que o número é encontrado. Então, uma vez que a matriz foi preenchida, nós iteramos através de sua lista de chaves ( ${!ll[@]}
) e imprimimos cada chave e seu valor (o número de vezes que foi visto).
Usando a GNU datamash
bin
opção:
datamash -s bin:1 1 < num | datamash -s -g 1 count 1
Saída:
24 3
25 4
26 1
29 1
30 3
Com o moleiro :
$> mlr --from data.txt --ocsv put '$1=int(ceil($1))' then count-distinct -f 1
1,count
31,3
30,1
27,1
26,4
25,3