Вместо того, чтобы пытаться сохранить все это в памяти, делайте это в несколько проходов.
Сначала создайте два файла, один для отдельных слов, а другой для биграмм.
Теперь, просмотрите ваш текст последовательно. Когда вы читаете каждое слово, выведите его в файл с одним словом. Объедините его с предыдущим словом и запишите пару в файл биграмм. Например, учитывая предложение «смысл в том, что нет смысла делать весь разговор бессмысленным», файл с одним словом будет содержать одно слово в строке. Файл биграммы будет содержать:
the point
point is
is that
that there
there is
...
Теперь, используя утилиту сортировки, предоставленную вашей операционной системой, сортируйте каждый файл. Это группирует идентичные слова вместе.
Затем напишите программу, которая читает файл построчно, считая идентичные строки. Получив общее количество слов, напишите соответствующий файл, содержащий word,count
. Так что если у вас есть:
apple
apple
banana
cherry
cherry
cherry
Тогда ваш вывод будет:
apple,2
banana,1
cherry,3
Сделайте то же самое с файлом биграмм.
Наконец, загрузите файл с одним словом в карту или словарь, проиндексированный по слову со значением, равным количеству. Три миллиона уникальных слов должны соответствовать. Если нет, вы можете поместить их в базу данных. Что-то вроде SQLite будет работать очень хорошо.
Тогда начните читать ваш файл биграммы. Каждая строка содержит биграмму и ее количество. Затем вы можете выполнить расчет и принять решение, хотите ли вы рассматривать его как одно слово, или вы можете вывести биграм с его счетом и счетом в отдельный файл и принять решение позже.
Вы можете уменьшить размер промежуточных файлов, созданных при первом проходе, сохранив некоторые данные в памяти. Вместо того, чтобы сразу записывать каждое слово и биграмму в промежуточный файл, сохраните в памяти два словаря и ограничьте их размер. Когда словарь заполнится, запишите слова и цифры на диск и очистите словарь. Таким образом, вместо сотен тысяч отдельных слов «the» в файле вы получите всего несколько «100000» записей.
Уменьшение размера промежуточных файлов увеличит скорость сортировки. На втором шаге, когда вы удаляете дубликаты, вы добавляете счетчики для каждой записи, а не просто добавляете один для каждой записи.
Выполнение этого за несколько проходов облегчает задачу, поскольку сокращает требуемую память, а каждый шаг почти тривиально прост. Конечно, это не так быстро, как однопрограммное решение. Но если это редкость, то кого это волнует, если это займет немного больше времени?
Еще одним преимуществом является то, что это решение является достаточно масштабируемым. Я сделал что-то очень похожее на своем ноутбуке (8 ГБ памяти), выполняя подсчеты слов и биграмм против загрузки всей английской Википедии. Это заняло некоторое время (несколько часов), но сработало хорошо.