Tenho um grande número de arquivos individuais que contêm seis colunas cada (o número de linhas pode variar). Como um exemplo simples:
1 0 0 0 0 0
0 1 1 1 0 0
Estou tentando identificar quantas colunas únicas tenho (ou seja, números e sua ordem coincidem), neste caso seria 3.
Existe uma linha simples para fazer isso? Eu sei que é fácil comparar uma coluna com outra coluna, mas como encontrar colunas idênticas?
Responder1
Você pode contar as colunas exclusivas com o seguinte canal:
$ awk '{for (i=1; i<=NF; ++i) a[i]=a[i]$i; } END { for (i in a) print a[i] }' foo \
| sort -u | wc -l
O comando awk transpõe sua entrada, as linhas resultantes são classificadas, apenas as linhas únicas são mantidas ( -u
) e no final todas as linhas (únicas) (ou seja, as colunas transpostas) são contadas ( wc -l
).
Observe que NF
é uma variável interna do awk e é automaticamente definida para o número de campos no registro atual. $i
faz referência ao i-ésimo campo e END
protege o bloco seguinte para que seja executado após todos os registros serem processados. O Awk usa por padrão a delimitação de campos em branco e não em branco.
Responder2
(((...))), mas como encontrar colunas idênticas?
$ printf '%s\n' '1 0 0 0 0 0' '0 1 1 1 0 0' | awk -vSUBSEP='=' '
{ for (i=1; i<NF; i++)
for (j=i+1; j<=NF; j++)
if ($i==$j)
M[i,j]++
}
END{ for (m in M) if (M[m]==NR) print m }'
5=6
2=3
2=4
3=4
Para todas as colunas i<j
de cada linha, aumente M[i,j]
sempre que os valores dessas colunas forem iguais. Portanto, M[i,j]==NR
depois de ler NR
as médias das linhas, os valores eram idênticos para todas as linhas lidas.
Responder3
Essa pergunta me interessou e eu queria seguir uma abordagem que não consegui descobrir exatamente e recebi uma ajuda maravilhosadepois que postei como uma pergunta diferente. Você pode entender a abordagem que estou tentando seguir com a pergunta que postei.
Eu tenho mais 2 soluções para este problema (uma deGnouc'sresposta que é umperlsolução e outra de Joãosolução combinada com a minha solução).
#The variable appended_input will remove spaces/tabs and just append the rows.
#Modify the file name in this line. Here I use inputfile as the filename.
appended_input=$(column -s '\t' inputfile | tr -d '[:space:]') ;
#The array variable will store each column-wise value as an array element.
#I use sort to find the number of unique elements.
array=($(
for ((i=0; i<6; i++))
do
new=${appended_input:$i:1}
for ((j=i+6; j<${#appended_input}; j=j+6))
do
new="$new${appended_input:$j:1}"
done
echo "$new"
done
)) | echo "${array[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '
Teste
Meu arquivo de entrada é como abaixo.
1 0 0 1 0 0
0 1 1 0 0 0
1 1 1 1 1 0
1 0 0 1 0 1
1 0 0 1 0 1
Depois de executar o script acima, recebo a saída como,
00011 00100 01100 10111
Você poderia ter a wc -w
como canal final e obteria a saída apenas 4 em vez dos valores de coluna exclusivos como acima.
Responder4
Aqui está uma gawk
solução que usa coprocessos para alimentar cada coluna para uma instância separada sha256sum
e relata o número total de hashes exclusivos (o número de hashes exclusivos deve coincidir com o número de colunas exclusivas, visto que a probabilidade de colisão de hash sha256sum
é estatisticamente insignificante). Embora alguns possam considerar isso um hack flagrante, uma vantagem que essa abordagem tem sobre algumas das outras é que ela não tenta concatenar/transpor os dados e, portanto, é relativamente eficiente em termos de memória.
awk 'BEGIN{for(i=1; i<=6; ++i){s=sprintf("%*s", i+1, ""); a[i]="sha256sum"s}}
{for (i=1; i<=6; ++i) print $i |& a[i]}
END{com= "sort | uniq | wc -l"
for (i=1; i<=6; ++i){close(a[i], "to"); a[i] |& getline x;
close(a[i]); print x | com};
close(com)}' file