Друк унікальних ліній


15

Чи є краще рішення для друку унікальних ліній, крім комбінації sortта uniq?


1
Що ви маєте на увазі під «кращим»?
габе.

@gabe Наприклад, не потрібно зберігати весь файл у пам'яті.
Let_Me_Be

Деякі версії sort(наприклад, GNU coreutils) використовують тимчасові файли та зовнішні об'єднання, якщо вхід занадто великий для розміщення в оперативній пам'яті. І в більшості інших версій є -mваріант, тому це можна зробити явно, відбиваючи вхід (наприклад, з split), сортуючи кожен фрагмент, а потім об'єднуючи шматки
jhnc

Відповіді:


25

Щоб надрукувати кожен однаковий рядок лише один, у будь-якому порядку:

sort -u

Щоб надрукувати лише унікальні лінії в будь-якому порядку:

sort | uniq -u

Щоб надрукувати кожен ідентичний рядок лише один раз у порядку їх першого появи: (для кожного рядка роздрукуйте рядок, якщо він ще не був помічений, то в будь-якому випадку збільшуйте помічений лічильник)

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

Щоб надрукувати лише унікальні рядки в порядку їх першого виникнення: (запишіть кожен рядок у seen, а також у тому linesвипадку, якщо це перше виникнення; наприкінці введення надрукуйте рядки у порядку появи, але лише ті, які бачили лише один раз)

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

8
як щодо awk '!seen[$0]++ {print}'?
asoundmove

10
Або навіть коротше awk '!seen[$0]++', оскільки значення {print}має на увазі порожня команда.
квазгар

3

Деякі (більшість?) Версій sortмають -uпрапор, який виконує uniqдеталь безпосередньо. Хоча це можуть бути деякі обмеження довжини рядків, залежно від реалізації, але у вас були такі, що вже мають простий sort|uniq.


1
Ер? sort -uповертається до V7 принаймні.
geekosaur

Гум ... Я думав, що пам’ятаю, що Соляріс або AIX не мали цього. Я помиляюсь, хоча у обох це є.
Мат

Solaris і AIX мають, -uале також мають обмеження довжини рядка 512 символів. (Насправді, я думаю, що десь навколо Solaris 9 Sun Sun збільшив її до 5120. Однак GNU все ще перемагає.)
geekosaur

@geekosaur: ви впевнені? Робота, спрямована на усунення 512-байтового обмеження довжини рядка у сортуванні, була задокументована у «Теорії та практиці в побудові робочого сортувального розпорядку» JP Linderman, Bell System Technical. Журнал, 63, 1827— 1843 (1984).
Джонатан Леффлер

0

Чи працює Perl для вас? Він може зберігати рядки в початковому порядку, навіть якщо дублікати не є суміжними. Ви також можете його кодувати в Python, або awk.

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

Яку можна скоротити до просто

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

Даний вхідний файл:

abc
def
abc
ghi
abc
def
abc
ghi
jkl

Це дає вихід:

abc
def
ghi
jkl

Де визначаються $ рядки?
Грегг Левенталь

Це не так. Оскільки немає use strict;або use warnings;(насправді, саме це strictє найбільш актуальним тут), скарги на використання %linesдо його визначення не існує. Якщо ви працюєте зі стриктурами, my %lines;перед циклом повинен бути рядок . Зауважте також, що хеш є %lines; один елемент хеша посилається на $lines{$_}позначення.
Джонатан Леффлер

Я думаю, що sortрішення можуть бути кращими для великого обсягу даних (ОП турбувалась про "збереження всього файлу в пам'яті"). sortбуде виконувати позасередовище, якщо дані більше, ніж наявна пам'ять.
Kusalananda

0

В останній частині відповіді, згаданої в: Друк унікальних ліній @Gilles як відповідь на це питання, я намагався усунути необхідність використання двох хешів.

Це рішення призначене для: Друку тільки унікальних рядків у порядку їх першого появи:

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

Тут "лічильник" зберігає кількість кожного рядка, схожого на оброблений раніше.
Наприкінці ми друкуємо лише ті рядки, які мають значення лічильника як 1.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.