Classificação GNU classificação estável quando a classificação não sabe a ordem de classificação

18

Eu tenho um arquivo de duas colunas; o arquivo está classificado da maneira que eu quero na coluna 1. Gostaria de classificar na coluna 2, dentro de cada categoria da coluna 1. No entanto, sortnão entende a ordem de classificação da coluna 1.

A maneira normal (a partir de perguntas semelhantes aqui na pilha) seria esta:

sort --stable -k1,1 -k2,2n

Mas não posso especificar a classificação no k1, porque é arbitrário.

Exemplo de entrada:

C 2
C 1
A 2
A 1
B 2 
B 1

e saída:

C 1
C 2
A 1
A 2
B 1 
B 2
Evan Benn
fonte

Respostas:

20

Você pode usar o awk para iniciar uma nova classificação para cada bloco:

% awk -v cmd="sort -k2,2" '$1 != prev {close(cmd); prev=$1} {print | cmd}' foo
C 1
C 2
A 1
A 2
B 1
B 2
  • $1 != prev {close(cmd); prev=$1} - quando o valor salvo é diferente, temos um novo bloco e fechamos todos os itens iniciados anteriormente sort
  • {print | "sort -k2,2"}'canaliza a saída sort, iniciando-a se ainda não estiver em execução (o awk pode acompanhar os comandos que inicia)
muru
fonte
2
awk é realmente incrível. Eu gosto muito mais do que aquilo que eu esperava, que foi uma decoração e decoração desajeitadas!
Evan Benn
Eu tentei comparar o desempenho desta vs a outra resposta, não sei por que esse usa mais recursos ... Alguma idéia? gist.github.com/EvanTheB/5b64eafb84eeaf51c289295ac06e1b0b
Evan Benn
Em quantas rodadas você teve média?
muru 31/07
Não calculei a média, mas estou vendo tempos de execução consistentes enquanto repito e investigo.
Evan Benn
Aqui está um arquivo semelhante ao que estou usando, se você deseja investigar:seq 30 | xargs -L1 bash -cs 'yes $1 | head -1000000 | paste - <(seq 1000000) | shuf' bash
Evan Benn
12

Você pode usar uma transformação Schwartziana (essa é basicamente a abordagem decorar-classificar-não-decorada a que você aludiu em um comentário, mas provavelmente com melhor desempenho do que a boa resposta de muru devido ao uso de uma única sortinvocação em oposição a várias) - usando awkuma coluna de prefixo que incrementa com uma alteração no valor na primeira coluna, classifique pela coluna do prefixo seguida pela coluna "segunda" (cuja posição ordinal mudou temporariamente para 3devido à presença da coluna do prefixo) e, finalmente, livre-se da coluna do prefixo

awk '{print ($1 in a? c+0: ++c)"\t" $0; a[$1]}' file | sort -k1,1n  -k3,3 | cut -f 2-
iruvar
fonte
Estou surpreso, mas você está correto, isso foi mais rápido que a outra resposta! 3 minutos vs 2 minutos no meu arquivo de 100 milhões de linhas (~ 30 primeiras colunas da uniq).
Evan Benn
11
Não é necessário manter uma matriz da chave exclusiva da primeira coluna. Eu acho que deveria ser suficiente comparar a primeira coluna da linha atual com a anterior.
Kusalananda
Algo como awk -v OFS="\t" '$1 != prev { key++ } { print key, $0; prev = $1 }(não testado).
Kusalananda