Como fazer a classificação personalizada usando a classificação unix?

11

Estou usando a classificação unix para classificar um arquivo delimitado por vírgula com várias colunas. Até agora, isso funcionou perfeitamente para classificar os dados numericamente ou em ordem alfabética:

Arquivo de exemplo antes de qualquer classificação:

C,United States,WA,Tacoma,f,1
A,United States,MA,Boston,f,0
B,United States,NY,New York,f,5
A,Canada,QC,Montreal,f,2
A,Bahamas,Bahamas,Nassau,f,2
A,United States,NY,New York,f,1

Classifique o arquivo: $ sort -t ',' -k 2,2 -k 3,3 -k 4,4 -k 5,5r -k 6,6nr tmp.csv

Resultado classificado:

A,Bahamas,Bahamas,Nassau,f,2
A,Canada,QC,Montreal,f,2
A,United States,MA,Boston,f,0
B,United States,NY,New York,f,5
A,United States,NY,New York,f,1
C,United States,WA,Tacoma,f,1

Aqui está o problema: desejo classificar a coluna 2 com base em uma classificação personalizada, o que significa que quero primeiro os Estados Unidos, depois o Canadá e as Bahamas:

Classificação desejada:

A,United States,MA,Boston,f,0
B,United States,NY,New York,f,5
A,United States,NY,New York,f,1
C,United States,WA,Tacoma,f,1
A,Canada,QC,Montreal,f,2
A,Bahamas,Bahamas,Nassau,f,2

Existe alguma maneira de passar à ordem do unix uma ordem de classificação personalizada que pode ser aplicada? Algo como: $ sort -t ',' -k 2,2:'United States, Canada, Bahamas' -k 3,3 -k 4,4 -k 5,5r -k 6,6nr tmp.csv

Obrigado!


fonte
3
Para esses três valores, você deseja ordem alfabética inversa. Para o caso geral, você precisará mapear os nomes para um número de ordem de classificação e, em seguida, fazer a classificação usando o número da ordem de classificação. Ou opte por uma linguagem de script ... Uma possibilidade é o joincomando, mas você pode acabar com muita classificação - os arquivos de entrada joindevem ser classificados em uma ordem e, em seguida, você estaria usando sortnovamente para colocar os dados em uma ordem diferente (e perder a coluna da ordem de classificação como uma etapa de pós-classificação).
Jonathan Leffler
Em sua entrada de exemplo, não deveria haver em tvez da fúltima linha?
Lev Levitsky
Lev: sim, boa captura. Foi mal; muito corte e colagem (meu conjunto de dados real é muito maior e acidentalmente peguei as linhas erradas).
Atualizei a resposta para corresponder aos seus dados.
Lev Levitsky

Respostas:

8

A outra resposta e comentário respondem à pergunta em geral, eis como uma implementação pode parecer:

$ cat order
Bahamas,3
Canada,2
United States,1

$ cat data
C,United States,WA,Tacoma,f,1
A,United States,MA,Boston,f,0
B,United States,NY,New York,f,5
A,Canada,QC,Montreal,f,2
A,Bahamas,Bahamas,Nassau,f,2
A,United States,NY,New York,f,1

$ sort -t, -k2 data | join -t, -11 -22 order - | sort -t, -k2n -k4,5 -k6r -k7nr | cut -d, -f 3,1,4-7
A,United States,MA,Boston,f,0
B,United States,NY,New York,f,5
A,United States,NY,New York,f,1
C,United States,WA,Tacoma,f,1
A,Canada,QC,Montreal,f,2
A,Bahamas,Bahamas,Nassau,f,2
Lev Levitsky
fonte
Incrível, obrigado por sua ajuda. Isso funcionou perfeitamente!
@jewelia Melhorado mais uma vez, sednão era realmente necessário aqui.
Lev Levitsky
1

Você não pode fazer isso com classificação . Neste ponto, você realmente deve procurar o awk / perl / seu-idioma-preferido . Você pode fingir, no entanto. Você pode, por exemplo, usar sed para alterar "Estados Unidos" para 0, "Canadá" para 1 e "Bahamas" para 2 e, em seguida, fazer uma classificação numérica nessa coluna e sedá-la novamente. Ou altere "Estados Unidos" para "Estados Unidos, 0" etc., classifique na coluna extra e depois a descarte.

itsbruce
fonte
0

Acabei de escrever um auxiliar chamado csort para facilitar isso. Ele prefixa cada linha com um valor de sua escolha, com base na correspondência de substring ou expressão regular na linha:

$ csort -t, '2=United States' X 2=Canada Y 2=Bahamas Z < tmp.csv | \
sort -t, -k1,1 -k3,3 -k4,4 -k5,5 -k6,6r -k7,7nr
X,A,United States,MA,Boston,f,0
X,B,United States,NY,New York,f,5
X,A,United States,NY,New York,f,1
X,C,United States,WA,Tacoma,f,1
Y,A,Canada,QC,Montreal,f,2
Z,A,Bahamas,Bahamas,Nassau,f,2

A 2=STRnotação significa "corresponder se o segundo campo for igual STR".

Você pode opcionalmente canalizar a saída cut -c3-para remover o prefixo.

Adam Spires
fonte