Impression de lignes uniques


15

Existe-t-il une meilleure solution pour imprimer des lignes uniques autres qu'une combinaison de sortet uniq?


1
Qu'entendez-vous par «mieux»?
gabe.

@gabe Ne nécessitant pas que le fichier entier soit stocké en mémoire par exemple.
Let_Me_Be

Certaines versions de sort(par exemple GNU coreutils) utilisent des fichiers temporaires et une fusion externe si l'entrée est trop grande pour tenir dans la RAM. Et la plupart des autres versions ont une -moption, ce qui peut être fait explicitement en découpant l'entrée (par exemple avec split), en triant chaque bloc, puis en fusionnant les morceaux
jhnc

Réponses:


25

Pour imprimer chaque ligne identique une seule, dans n'importe quel ordre:

sort -u

Pour imprimer uniquement les lignes uniques, dans n'importe quel ordre:

sort | uniq -u

Pour imprimer chaque ligne identique une seule fois, dans l'ordre de leur première occurrence: (pour chaque ligne, imprimez la ligne si elle n'a pas encore été vue, puis en tout cas incrémentez le compteur vu)

awk '!seen[$0] {print}
     {++seen[$0]}'

Pour imprimer uniquement les lignes uniques, dans l'ordre de leur première occurrence: (enregistrez chaque ligne dans seenet aussi liness'il s'agit de la première occurrence; à la fin de l'entrée, imprimez les lignes dans l'ordre d'occurrence mais uniquement celles vues uniquement une fois que)

awk '!seen[$0]++ {lines[i++]=$0}
     END {for (i in lines) if (seen[lines[i]]==1) print lines[i]}'

8
que diriez-vous awk '!seen[$0]++ {print}'?
asoundmove

10
Ou encore plus court awk '!seen[$0]++', car le {print}est impliqué par une commande vide.
quazgar

3

Certaines (la plupart?) Versions sortont un -uindicateur qui fait uniqdirectement la partie. Il peut y avoir des restrictions de longueur de ligne en fonction de l'implémentation, mais vous en aviez déjà avec plain sort|uniq.


1
Euh? sort -uremonte au moins à V7.
geekosaur

Hum ... Je pensais que je me souvenais que Solaris ou AIX n'en avaient pas. Je me trompe cependant, ils l'ont tous les deux.
Mat

Solaris et AIX ont -umais ont également une restriction de longueur de ligne de 512 caractères. (En fait, je pense que quelque part autour de Solaris 9 Sun l'a augmenté à 5120. GNU gagne toujours, cependant.)
geekosaur

@geekosaur: êtes-vous sûr? Le travail effectué pour supprimer la limite de 512 octets sur la longueur de ligne en tri a été documenté dans «Théorie et pratique dans la construction d'une routine de tri de travail» par JP Linderman, Bell System Technical. Journal, 63, 1827 à 1843 (1984).
Jonathan Leffler

0

Perl fonctionne-t-il pour vous? Il peut conserver les lignes dans l'ordre d'origine, même si les doublons ne sont pas adjacents. Vous pouvez également le coder en Python, ou awk.

while (<>) {
    print if $lines{$_}++ == 0;
}

Qui peut être raccourci à seulement

perl -ne 'print unless $lines{$_}++;'

Fichier d'entrée donné:

abc
def
abc
ghi
abc
def
abc
ghi
jkl

Il donne la sortie:

abc
def
ghi
jkl

Où les lignes $ sont-elles définies?
Gregg Leventhal

Ça ne l'est pas. Puisqu'il n'y a pas de use strict;ou use warnings;(en fait, c'est ce strictqui est le plus pertinent ici), il n'y a pas de problème d'utilisation %linesavant qu'il ne soit défini. S'il est exécuté avec des restrictions, il devrait y avoir une ligne my %lines;avant la boucle. Notez également que le hachage est %lines; un élément du hachage est référencé à l'aide de la $lines{$_}notation.
Jonathan Leffler

Je pense que les sortsolutions peuvent être meilleures pour une grande quantité de données (l'OP s'inquiétait de "stocker le fichier entier en mémoire"). sorteffectuera un tri hors cœur si les données sont plus grandes que la mémoire disponible.
Kusalananda

0

Pour la dernière partie de la réponse mentionnée dans: Impression de lignes uniques par @Gilles comme réponse à cette question, j'ai essayé d'éliminer la nécessité d'utiliser deux hachages.

Cette solution est pour: Pour imprimer uniquement les lignes uniques, dans l'ordre de leur première occurrence:

awk '{counter[$0]++} END {for (line in counter) if (counter[line]==1) print line}'

Ici, "compteur" stocke un nombre de chaque ligne similaire à celui traité précédemment.
À la fin, nous imprimons uniquement les lignes dont la valeur de compteur est 1.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.