Comment faire un tri personnalisé en utilisant le tri Unix?

11

J'utilise le tri Unix pour trier un fichier délimité par des virgules avec plusieurs colonnes. Jusqu'à présent, cela a parfaitement fonctionné pour trier les données soit numériquement soit par ordre alphabétique:

Exemple de fichier avant tout tri:

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

Triez le fichier: $ sort -t ',' -k 2,2 -k 3,3 -k 4,4 -k 5,5r -k 6,6nr tmp.csv

Résultat trié:

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

Voici le problème: je veux trier la colonne 2 en fonction d'un tri personnalisé, ce qui signifie que je veux d'abord les États-Unis, puis le Canada, puis les Bahamas:

Tri souhaité:

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-t-il un moyen de passer le tri Unix un ordre de tri personnalisé qu'il peut ensuite appliquer? Quelque chose comme: $ sort -t ',' -k 2,2:'United States, Canada, Bahamas' -k 3,3 -k 4,4 -k 5,5r -k 6,6nr tmp.csv

Merci!


la source
3
Pour ces trois valeurs, vous souhaitez inverser l'ordre alphabétique. Dans le cas général, vous devrez mapper les noms à un numéro d'ordre de tri, puis effectuer le tri à l'aide du numéro d'ordre de tri. Ou optez pour un langage de script ... Une possibilité est la joincommande, mais vous pourriez vous retrouver avec beaucoup de tri - les fichiers d'entrée pour joindoivent être triés dans un ordre, puis vous utiliseriez à sortnouveau pour mettre les données dans un ordre différent (et la perte de la colonne d'ordre de tri en tant qu'étape de post-tri).
Jonathan Leffler
Dans votre exemple d'entrée, ne devrait-il pas y en avoir tau lieu de fdans la dernière ligne?
Lev Levitsky
Lev: oui, bonne prise. Ma faute; trop de couper et coller (mon ensemble de données réel est beaucoup plus grand et j'ai accidentellement saisi les mauvaises lignes).
J'ai mis à jour la réponse pour correspondre à vos données.
Lev Levitsky

Réponses:

8

L'autre réponse et commentaire répondent à la question en général, voici à quoi peut ressembler une implémentation:

$ 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
la source
Génial, merci pour votre aide. Cela a parfaitement fonctionné!
@jewelia Amélioré une fois de plus, sedn'était pas vraiment nécessaire ici.
Lev Levitsky
1

Vous ne pouvez pas faire ça avec le tri . À ce stade, vous devriez vraiment atteindre awk / perl / votre-langue-de-choix . Vous pouvez le truquer, cependant. Vous pouvez, par exemple, utiliser sed pour remplacer «États-Unis» par 0, «Canada» par 1 et «Bahamas» par 2, puis effectuer un tri numérique par rapport à cette colonne, puis la redéfinir. Ou changez «États-Unis» en «États-Unis, 0», etc., triez dans la colonne supplémentaire, puis jetez-la.

itsbruce
la source
0

Je viens d'écrire un assistant appelé csort pour vous faciliter la tâche. Il préfixe chaque ligne avec une valeur de votre choix en fonction de la sous-chaîne ou des correspondances d'expressions régulières dans la ligne:

$ 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

La 2=STRnotation signifie "correspond si le deuxième champ est égal STR".

Vous pouvez ensuite éventuellement canaliser la sortie cut -c3-pour supprimer le préfixe.

Adam Spires
la source