удаление дубликатов из списка без сохранения списка в памяти

2

Я пытаюсь найти эффективный способ удаления дубликатов строк из файла без чтения всего содержимого файла в памяти. Файл произвольно упорядочен. Я пытаюсь не читать его в памяти, потому что файл слишком большой (20GB+). Может ли кто-нибудь предложить способ исправить мой код, чтобы он не читал весь файл в памяти?

val oldFile="steam_out_scala.txt"
val noDupFile="nodup_steam_out.txt"

import scala.io.Source
import java.io.{FileReader, FileNotFoundException, IOException}
import java.io.FileWriter;
import scala.collection.mutable.ListBuffer

var numbers = new ListBuffer[String]()
val fw = new FileWriter(noDupFile, true) 

for (line <- Source.fromFile(oldFile).getLines()) {
    numbers+=line

}

numbers.distinct.foreach((x)=>{
    //println(x)
    fw.write(x)
})
fw.close()    

Что я знаю о данных:

каждая строка длинная: 76561193756669631 он не упорядочен, и конечный результат не нужно заказывать каким-либо образом список был сгенерирован с использованием другой программы. Число может быть повторено (0,4 миллиона)
  • 1
    Рассчитайте хеш-функцию (например, MD5), чтобы суммировать каждую строку и сохранить их в памяти. Если хеш-функция строки является дубликатом, пропустите эту строку. Это иногда будет пропускать слишком много, но это просто и может быть сделано за один просмотр файла. Если дедупликация не должна пропускать уникальные строки, добавьте слой (медленной) двойной проверки.
  • 0
    Что вы знаете о числах в файле данных? Вы можете использовать байтовый массив для представления этих чисел, а затем один раз передать массив, чтобы восстановить уникальные числа.
Показать ещё 2 комментария
Теги:
performance
out-of-memory

2 ответа

1
Лучший ответ

Вы можете решить эту проблему несколькими способами:

1) Прочитайте исходный файл по строкам и перед добавлением его в новый файл, который содержит только уникальные строки, проверяет этот файл, если такая строка уже существует. Это будет довольно медленным, потому что O(n^2).

Код будет выглядеть примерно так:

val oldFile="steam_out_scala.txt"
val noDupFile="nodup_steam_out.txt"

import scala.io.Source
import java.io.{FileReader, FileNotFoundException, IOException}
import java.io.FileWriter;
import scala.collection.mutable.ListBuffer

var numbers = new ListBuffer[String]()
val fw = new FileWriter(noDupFile, true) 

for (line <- Source.fromFile(oldFile).getLines()) {
    if(Source.fromFile(noDupFile).getLines().forall(!_.equals(line))) {
        fw.write(line)
    }
}

fw.close()

2) Вы можете выполнить так называемую внешнюю сортировку, которая была изобретена именно для сортировки больших объемов данных, которые не вписываются в память и быстрее, чем описанный выше метод. Он сортирует небольшие фрагменты всего набора данных (который может вписываться в память), сохраняет их во временных файлах и затем объединяет их. Удовлетворительный факт, если у вашей ОС есть опция виртуальной памяти, тогда ОС будет делать что-то подобное для вас, поменяв данные, которые не помещаются в память на жесткий диск.

Это универсальные решения, которые будут работать с любыми данными. Если вы можете предоставить более подробную информацию о содержании файла, мы могли бы придумать что-то более умное.

  • 0
    Ваш код решил проблему, но вы были правы насчет сложности времени. Я пытался найти простой внешний вид, но не смог найти реализацию, которая имела бы смысл. Есть ли шанс, что вы могли бы объяснить концепцию? Или это должен быть новый вопрос?
  • 0
    Вы смотрели на страницу Википедии @ Rilcon42, на которую ссылались?
Показать ещё 1 комментарий
0

Вы можете использовать фильтр цветения (https://en.m.wikipedia.org/wiki/Bloom_filter), чтобы удалить дублирование из файла

Ещё вопросы

Сообщество Overcoder
Наверх
Меню