Как удалить повторяющиеся строки внутри текстового файла?

Мой огромный (до 2 ГиБ) текстовый файл содержит около 100 точных дубликатов каждой строки в нем (бесполезно в моем случае, поскольку файл представляет собой таблицу данных в формате CSV).

Что мне нужно, так это удалить все повторы при сохранении (желательно, но этим можно пожертвовать ради значительного повышения производительности) исходного порядка последовательностей. В результате каждая строка должна быть уникальной. Если бы было 100 одинаковых строк (обычно дубликаты разбросаны по файлу и не будут соседями), останется только одна такая же.

Я написал программу на Scala ( считайте это Java, если вы не знаете о Scala), чтобы реализовать это. Но, может быть, есть более быстрые собственные инструменты, написанные на C, которые могут сделать это быстрее?

ОБНОВЛЕНИЕ: казалось, что решение awk '! Seen [$ 0] ++' filename работает нормально для меня, пока файлы были около 2 ГиБ или меньше, но теперь, когда я должен очистить файл размером 8 ГиБ, он больше не работает. Кажется, что бесконечность на Mac с 4 ГиБ ОЗУ и 64-битном ПК с Windows 7 с 4 ГиБ ОЗУ и подкачкой 6 ГиБ просто исчерпывается. И я не испытываю энтузиазма по поводу того, чтобы пробовать его в Linux с 4 ГиБ ОЗУ, учитывая этот опыт.


Решение awk , которое можно увидеть на #bash (Freenode):

  awk '! Seen [$ 0] ++' filename  

Существует простой (не сказать очевидный) метод с использованием стандартных утилит, который не требует большого объема памяти, за исключением запуска sort , который в большинстве реализаций есть специальные оптимизации для огромных файлов (хороший алгоритм внешней сортировки). Преимущество этого метода в том, что он перебирает только все строки внутри специальных утилит, а не внутри интерпретируемых языков.

   output # удалить номера строк  

Если все строки начинаются с непробельного символа, вы можете обойтись без некоторых из опций:

   output  

Для большого количества дублирований лучше подойдет метод, требующий сохранения только одной копии каждой строки в памяти. С некоторыми накладными расходами на интерпретацию для этого есть очень сжатый сценарий awk (уже опубликованный enzotib):

    

Менее кратко: ! seen [$ 0] {print} {seen [$ 0] + = 1} , т.е. распечатать текущую строку, если она не была видно, а затем увеличьте счетчик visible для этой строки (неинициализированные переменные или элементы массива имеют числовое значение 0).

Для длинных строк вы можете сэкономить память сохраняя только неконтролируемую контрольную сумму (например, криптографический дайджест) каждой строки. Например, при использовании SHA-1 вам нужно всего 20 байтов плюс постоянные накладные расходы на строку.. Но вычисление дайджестов происходит довольно медленно; этот метод будет успешным только в том случае, если у вас есть быстрый ЦП (особенно с аппаратным ускорителем для вычисления дайджестов) и небольшой объем памяти относительно размера файла и достаточно длинные строки. Никакая базовая утилита не позволяет вычислять контрольную сумму для каждой строки; вам придется нести накладные расходы на интерпретацию Perl/Python/Ruby/… или написать специальную скомпилированную программу.

   output  


Существует простой (что не сказать очевидный) метод с использованием стандартных утилит, который не требует большой памяти, за исключением запуска sort , который в большинстве реализаций имеет определенные оптимизации для огромные файлы (хороший алгоритм внешней сортировки). Преимущество этого метода в том, что он перебирает только все строки внутри специальных утилит, а не внутри интерпретируемых языков.

   output # удалить номера строк  

Если все строки начинаются с непробельного символа, вы можете обойтись без некоторых из опций:

   output  

Для большого количества дублирований лучше подойдет метод, требующий сохранения только одной копии каждой строки в памяти. С некоторыми накладными расходами на интерпретацию для этого есть очень сжатый сценарий awk (уже опубликованный enzotib):

    

Менее кратко: ! seen [$ 0] {print} {seen [$ 0] + = 1} , т.е. распечатать текущую строку, если она не была видно, а затем увеличьте счетчик visible для этой строки (неинициализированные переменные или элементы массива имеют числовое значение 0).

Для длинных строк вы можете сэкономить память сохраняя только неконтролируемую контрольную сумму (например, криптографический дайджест) каждой строки. Например, при использовании SHA-1 вам нужно всего 20 байтов плюс постоянные накладные расходы на строку. Но вычисление дайджестов происходит довольно медленно; этот метод будет успешным только в том случае, если у вас есть быстрый ЦП (особенно с аппаратным ускорителем для вычисления дайджестов) и небольшой объем памяти относительно размера файла и достаточно длинные строки. Никакая базовая утилита не позволяет вычислять контрольную сумму для каждой строки; вам придется нести накладные расходы на интерпретацию Perl/Python/Ruby/… или написать специальную скомпилированную программу.

   output  

  sort -u big-csv-file.csv> duplicates-deleted.csv  

Обратите внимание, что выходной файл будет отсортирован.


  sort -u big-csv-file.csv> дубликаты-удалены.  csv  

Обратите внимание, что выходной файл будет отсортирован.


Предполагая, что вы можете позволить себе хранить в памяти столько же дедуплицированного файла (если ваши данные действительно дублируются в 100 раз, это должно составлять около 20 МБ + накладные расходы), вы можете легко сделать это с помощью Perl.

  $ perl -ne 'print, если $ dup {$ _} ++;'  input_file> output_file  

Это тоже сохраняет порядок.

Вы можете извлечь количество вхождений каждой строки из % dup хеш, если хотите, в качестве дополнительного бесплатного бонуса.

Если вы предпочитаете awk , это тоже должно сработать (та же логика, что и у perl версия, тот же порядок, те же данные, собранные в переменной dup ):

  $ awk '{if (++ dup [$ 0] =  = 1) print $ 0;} 'input_file> output_file  


Предполагая, что вы можете позволить себе хранить в памяти столько же, сколько дедуплицированный файл (если ваши данные действительно дублируются в 100 раз, это должно составлять около 20 МБ + накладные расходы), вы можете легко сделать это с помощью Perl.

  $ perl -ne 'print, если $ dup {$ _} ++;'  input_file> output_file  

Это также сохраняет порядок.

Вы можете извлечь количество вхождений каждой строки из % dup хеш, если хотите, в качестве дополнительного бесплатного бонуса.

Если вы предпочитаете awk , это тоже должно сработать (та же логика, что и у perl версия, тот же порядок, те же данные, собранные в переменной dup ):

  $ awk '{if (++ dup [$ 0] =  = 1) print $ 0;} 'input_file> output_file  

Как никакой другой ответ на месте support, вот один:

  gawk -i inplace '! a [$ 0] ++' файл  


Поскольку никакой другой ответ не обеспечивает поддержку на месте, вот один:

  gawk -i inplace '! a [$ 0] ++' file  

Вы можете использовать uniq http://www .computerhope.com/unix/uuniq.htm

uniq re портирует или отфильтровывает повторяющиеся строки в файле.


Вы можете использовать uniq http://www. computerhope.com/unix/uuniq.htm

uniq сообщает или отфильтровывает повторяющиеся строки в файле.


Лайнеры Python One:

  python -c "import sys  ;  lines = sys.stdin.readlines ();  Распечатать ''. join (sorted (set (lines))) " 


Лайнеры Python One:

  python -c "import sys;  lines = sys.stdin.readlines ();  print '' .join (sorted (set (lines))) " 

Ни один из ответов здесь не помог мне на моем Mac, поэтому я написал простой скрипт Python, который работает для меня. Я игнорирую начальные/конечные пробелы, а также не забочусь о потреблении памяти.

  import sysinputfile = sys.argv [1] outputfile = sys.argv [2] с открытым (входным файлом) как f: content = f.readlines () content = [x.strip () для x в содержимом] my_list  = list (set (content)) с open (outputfile, 'w') в качестве вывода: для элемента в my_list: output.write ("% s  n"% item)  

Сохраните указанное выше в unique.py и запустите следующим образом:

  python unique.py inputfile.txt outputfile.txt  


Ни один из ответов здесь не сработал для меня на моем Mac, поэтому я написал простой скрипт python, который работает для меня. Я игнорирую ведущие/конечные пробелы, а также не забочусь о памяти потребление.

  import sysinputfile = sys.argv [1] outputfile = sys.argv [2] с открытым (входным файлом) как f: content = f.readlines () content = [x.  strip () для x в содержимом] my_list = list (set (content)) с open (outputfile, 'w') в качестве вывода: для элемента в my_list: output.write ("% s  n"% item)  

Сохраните указанное выше в unique.py и запустите следующим образом:

  python unique.py inputfile.txt outputfile.txt   

РЕШЕНИЕ БЕЗ ПОДДЕРЖКИ ИСХОДНОГО ПОРЯДКА ПОСЛЕДОВАТЕЛЬНОСТИ

Я сделал это с помощью следующего фрагмента кода.

  sort duplicates.txt |  uniq> noDuplicates.txt  

Команда sort сортирует строки в алфавитном порядке, а команда uniq удаляет дубликаты.

ПРИМЕЧАНИЕ. Почему мы сначала отсортировали строки, так это то, что uniq не обнаруживает повторяющиеся строки если они не расположены рядом.


РЕШЕНИЕ БЕЗ ПОДДЕРЖКИ ИСХОДНОЙ ПОСЛЕДОВАТЕЛЬНОСТИ ЗАКАЗ

Я сделал это с помощью следующего фрагмента кода.

  sort duplicates.txt |  uniq> noDuplicates.txt  

Команда sort сортирует строки в алфавитном порядке, а команда uniq удаляет дубликаты.

ПРИМЕЧАНИЕ. Почему мы сначала отсортировали строки, так это то, что uniq не обнаруживает повторяющиеся строки если они не смежные.


С bash 4 решение на чистом bash, использующее преимущества ассоциативных массивов, может быть используемый. Вот пример

  unset llist;  объявить -A llist; при чтении -r строка;  doif [[$ {llist [$ line]}]];  затем continueelse printf '% s  n' "$ line" llist [$ line] = "x" fidone  


С bash 4 можно использовать решение на чистом bash, которое использует преимущества ассоциативных массивов. Вот пример

  unset llist;  объявить -A llist; при чтении -r строка;  doif [[$ {llist [$ line]}]];  затем continueelse printf '% s  n' "$ line" llist [$ line] = "x" fidone  

Оцените статью
techsly.ru
Добавить комментарий