Drukowanie unikalnych linii

15

Czy istnieje jakieś lepsze rozwiązanie do drukowania unikatowych linii inne niż kombinacja sorti uniq?

Zostaw mnie w spokoju
źródło
1
Co rozumiesz przez „lepszy”?
Gabe.
@ gabe Nie wymaga na przykład przechowywania całego pliku w pamięci.
Let_Me_Be
Niektóre wersje sort(np. GNU coreutils) używają plików tymczasowych i zewnętrznego scalania, jeśli dane wejściowe są zbyt duże, aby zmieścić się w pamięci RAM. I większość innych wersji ma -mopcję, więc można to zrobić jawnie, dzieląc dane wejściowe (np. Za pomocą split), sortując każdy fragment, a następnie łącząc fragmenty
jhnc

Odpowiedzi:

25

Aby wydrukować każdy identyczny wiersz tylko jeden, w dowolnej kolejności:

sort -u

Aby wydrukować tylko unikalne linie, w dowolnej kolejności:

sort | uniq -u

Aby wydrukować każdą identyczną linię tylko raz, w kolejności ich pierwszego wystąpienia: (dla każdej linii wydrukuj linię, jeśli jeszcze nie była widoczna, to w każdym razie zwiększ licznik widoczności)

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

Aby wydrukować tylko unikalne wiersze, w kolejności ich pierwszego wystąpienia: (zapisz każdą linię seen, a także linesjeśli jest to pierwsze wystąpienie; na końcu danych wejściowych wydrukuj linie w kolejności występowania, ale tylko te widoczne tylko pewnego razu)

awk '!seen[$0]++ {lines[i++]=$0}
     END {for (i in lines) if (seen[lines[i]]==1) print lines[i]}'
Gilles „SO- przestań być zły”
źródło
8
jak o awk '!seen[$0]++ {print}'?
asoundmove
10
Lub nawet krócej awk '!seen[$0]++', ponieważ {print}implikuje to puste polecenie.
quazgar
3

Niektóre (większość?) Wersje sortmają -uflagę, która wykonuje uniqczęść bezpośrednio. Może to być pewne ograniczenia długości linii w zależności od implementacji, ale masz już te z prostym sort|uniq.

Mata
źródło
1
Eee? sort -uwraca co najmniej do V7.
geekozaur
Hum ... Myślałem, że pamiętam brak Solaris lub AIX. Jednak się mylę, oboje to mają.
Mat
Solaris i AIX mają, -uale mają również ograniczenie długości linii do 512 znaków. (Właściwie myślę, że gdzieś w okolicach Solaris 9 Sun podniosło go do 5120. GNU wciąż wygrywa.)
geekozaur
@geekosaur: jesteś pewien? Praca wykonana w celu usunięcia 512-bajtowego ograniczenia długości linii w sortowaniu została udokumentowana w „Teorii i praktyce w konstrukcji rutyny sortowania roboczego” JP Lindermana, Bell System Technical. Journal, 63, 1827–1843 (1984).
Jonathan Leffler
0

Czy Perl działa dla ciebie? Może zachować wiersze w oryginalnej kolejności, nawet jeśli duplikaty nie sąsiadują ze sobą. Możesz go również zakodować w Pythonie lub awk.

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

Które można skrócić do sprawiedliwego

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

Podany plik wejściowy:

abc
def
abc
ghi
abc
def
abc
ghi
jkl

Daje to wynik:

abc
def
ghi
jkl
Jonathan Leffler
źródło
Gdzie są definiowane linie $?
Gregg Leventhal
To nie jest Ponieważ nie ma use strict;ani use warnings;(a właściwie jest strictto najbardziej istotne w tym przypadku), nie ma żadnych skarg dotyczących używania %linesprzed jego zdefiniowaniem. Jeśli biegniesz z ograniczeniami, my %lines;przed pętlą musi być linia . Zauważ też, że hash jest %lines; do jednego elementu skrótu odwołuje się za pomocą $lines{$_}notacji.
Jonathan Leffler
Myślę, że sortrozwiązania mogą być lepsze dla dużej ilości danych (OP był zaniepokojony „przechowywaniem całego pliku w pamięci”). sortwykona sortowanie poza rdzeniem, jeśli dane są większe niż dostępna pamięć.
Kusalananda
0

Dla ostatniej części odpowiedzi wymienionej w: Drukowanie unikalnych linii przez @Gilles jako odpowiedź na to pytanie, starałem się wyeliminować potrzebę używania dwóch skrótów.

To rozwiązanie dotyczy: Aby wydrukować tylko unikalne linie, w kolejności ich pierwszego wystąpienia:

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

Tutaj „licznik” przechowuje liczbę każdej linii, która jest podobna do tej przetwarzanej wcześniej.
Na koniec drukujemy tylko te linie, które mają wartość licznika jako 1.

Sarfraaz Ahmed
źródło