Drukowanie unikalnych linii


15

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


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]}'

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.


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

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.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.