Як отримати лише унікальні результати, не сортуючи дані?


40
$ cat data.txt 
aaaaaa
aaaaaa
cccccc
aaaaaa
aaaaaa
bbbbbb
$ cat data.txt | uniq
aaaaaa
cccccc
aaaaaa
bbbbbb
$ cat data.txt | sort | uniq
aaaaaa
bbbbbb
cccccc
$

Результатом, який мені потрібен, є відображення всіх рядків з оригінального файлу, видалення всіх дублікатів (не тільки послідовних), зберігаючи початковий порядок висловлювань у файлі .

Ось, у цьому прикладі, результат, який я насправді шукав, був

aaaaaa
cccccc
bbbbbb

Як я можу виконати цю узагальнену uniqоперацію взагалі?

Відповіді:


54
perl -ne 'print unless $seen{$_}++' data.txt

Або, якщо ви повинні використовувати марноcat :

cat data.txt | perl -ne 'print unless $seen{$_}++'

Ось awkпереклад для систем, яким не вистачає Perl:

awk '!seen[$0]++' data.txt
cat data.txt | awk '!seen[$0]++'

3
Трохи коротший сценарій awk{ if (!seen[$0]++) print }
1111

1
@fred, якщо ваш файл справді величезний, для запуску будь-якої версії потрібно більше часу, ніж для запуску.
cjm

8
Версія AWK можна зробити ще коротше, залишивши поза if, print, дужки і фігурні дужки:awk '!seen[$0]++'
Гордон Девіссон

2
@Legate, це ім'я масиву, в який ми записуємо кожен список, який ми бачили. Ви можете змінити це на '!LarryWall[$0]++'всі неприємні турботи, але "побачене" допомагає людям краще зрозуміти програму.
cjm

1
@Sadi, це справді слід було б задати як питання, а не коментар. Але деякі рядки у цьому файлі закінчуються пробілом, а деякі - ні. Ці команди вважають весь рядок значущим, включаючи пробіли в кінці.
cjm

13

У Джона є інструмент під назвою unique:

usr@srv % cat data.txt | unique out
usr@srv % cat out
aaaaaa
cccccc
bbbbbb

Домогтися того ж без додаткових інструментів в одному командному рядку трохи складніше:

usr@srv % cat data.txt | nl | sort -k 2 | uniq -f 1 | sort -n | sed 's/\s*[0-9]\+\s\+//'
aaaaaa
cccccc
bbbbbb

nlдрукує номери рядків перед рядками, тому, якщо ми sort/ uniqза ними, ми можемо відновити початковий порядок рядків. sedпросто видаляє номери рядків після цього;)


Чи є комбінація загальних команд Linux, які могли б зробити те саме?
Лазер

7
Що ви пропустили у "без необхідності сортувати дані"?
Тотор

@Totor - см menkus " відповідь на аналогічне зауваження. @binfalse - ваше друге рішення не працює (можливо, воно працює з цим тривіальним зразком, але воно не працює з деякими вкладеннями в реальному житті). Виправте це, наприклад, це завжди має працювати:nl -ba -nrz data.txt | sort -k2 -u | sort | cut -f2
don_crissti

6

Я вважаю за краще використовувати це:

cat -n data.txt | sort --key=2.1 -b -u | sort -n | cut -c8-

cat -n додає номери рядків,

sort --key=2.1 -b -u сортування у другому полі (після доданих номерів рядків), ігнорування провідних пробілів, зберігання унікальних ліній

sort -n сортування в строгому числовому порядку

cut -c8- зберегти всі символи з стовпця 8 до EOL (тобто опустити цифри рядків, які ми включили)


5
> Як отримати лише унікальні результати, не сортуючи дані? > без сортування даних
Jan Wikholm

7
"без сортування даних" відображається лише в заголовку. Фактична потреба полягає в тому, щоб "відобразити всі рядки з оригінального файлу, видаливши всі дублікати (не тільки послідовні), зберігаючи початковий порядок висловлювань у файлі."
menkus

1
@menkus ключ "зберігаючи початковий порядок висловлювань у файлі". Ця відповідь цього не досягає.
Ендрю Фер’є

2

У Perl є модуль, який ви можете використовувати, який включає функцію під назвою uniq. Отже, якщо ви даєте свої дані, завантажені в масив в Perl, ви просто викликаєте функцію на зразок цієї, щоб зробити її унікальною, але все одно підтримувати початковий порядок.

use List::MoreUtils qw(uniq)    
@output = uniq(@output);

Детальніше про цей модуль можна прочитати тут: Список :: MoreUtils


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