Сортировка строк в большом файле
Имеется текстовый файл, в котором есть 150млн рандомных строчек (a-z). В этом файле нужно отсортировать строки по первой букве в алфавитном порядке. Ограничение: если во время сортировки нашлось больше чем 30к строчек на 1 букву, то нужно создать новый файл и закинуть туда остаток.
Ответы (1 шт):
Автор решения: CrazyElf
→ Ссылка
Ну, сделайте так, если я всё правильно понял.
- Создайте и откройте на запись файлы на каждую букву латинского алфавита от
a.txtдоz.txt - Пройдите по вашему файлу и допишите каждую строку в файл, соответствующий первой букве этой строки.
- Теперь по очереди прочитайте содержимое файлов от
a.txtдоz.txt, записывая строки подряд в новый файл. Когда число записанных строк превышает ограничение - открывайте новый файл и пишите дальше туда.
Набросал код, включая создание входного файла, чтобы сразу протестировать это всё. На Google Colab файл в 15 млн. строк создаётся минуту и разбирается потом за 15 секунд. 150 млн. не пробовал, но, наверное, будет в 10 раз дольше, масштабируется тут всё линейно.
from random import choices
from tqdm.auto import tqdm
class LetterFile:
def __init__(self, letter, max_lines):
self.letter = letter
self.number = 0
self.line_count = 0
self.max_lines = max_lines
self.create()
def create(self):
self.open('w')
def open(self, mode = 'w+'):
self.file = open(self.letter + str(self.number) + '.txt', mode)
def close(self):
self.file.close()
def append(self, line):
self.file.write(line)
self.line_count += 1
if self.line_count >= self.max_lines:
self.close()
self.number += 1
self.line_count = 0
self.open()
def get_latin_letters():
for ch in range(ord('a'), ord('z') + 1):
yield chr(ch)
input_file_name = 'data.txt'
input_file_rows = 15_000_000
max_lines = 30_000
str_len = 15
alphabet = list(get_latin_letters())
print(*alphabet)
print('generating input file')
with open(input_file_name, 'w') as f:
for i in tqdm(range(input_file_rows)):
s = ''.join(choices(alphabet, k=str_len))
f.write(s)
f.write('\n')
files = {}
print('create files')
for ch in alphabet:
f = LetterFile(ch, max_lines)
files[ch] = f
print('process input file')
with open(input_file_name) as fr:
for s in tqdm(fr.readlines()):
fw = files[s[0]]
fw.append(s)
print('closing files')
for ch in alphabet:
f = files[ch]
f.close()
Нумерация файлов такая: a0, a1 и т.д. Поменять её легко если что.