slurp/csv/loop файл для создания списка словарей

У меня есть большой файл (1,6 гигабайта) с миллионами строк, столбцы которых разделены:

[||]

Я пытался использовать модуль CSV, но он говорит, что я могу использовать только один символ в качестве разделителя. Итак, вот что я имею:

fileHandle = open('test.txt', 'r', encoding="UTF-16")

thelist = []

for line in fileHandle:
    fields = line.split('[||]')

    therow = {
        'dea_reg_nbr':fields[0],
        'bus_actvty_cd':fields[1],
        'drug_schd':fields[3],
        #50 more columns like this
    }
    thelist.append(therow)

fileHandle.close()

#now I have thelist which is what I want

И бум, теперь у меня есть список словарей, и это работает. Я хочу список, потому что я забочусь о порядке, и словарь, потому что вниз по течению это ожидается. Такое ощущение, что я должен воспользоваться чем-то более эффективным. Я не думаю, что это хорошо масштабируется с более чем миллионом строк и таким большим количеством данных. Итак, мой вопрос таков:

Что может быть более эффективным способом получения многосимвольного текстового файла с разделителями (в кодировке UTF-16) и создания списка словарей?

Любые мысли будут оценены!

1 ответ

Решение

Один из способов улучшить его масштабирование - использовать генератор вместо загрузки всех миллионов строк в память одновременно. Это может или не может быть возможно в зависимости от вашего варианта использования; это будет работать лучше всего, если вам нужно всего лишь сделать один проход для полного набора данных. Многократные проходы потребуют, чтобы вы либо сохранили все данные в памяти в той или иной форме, либо считывали их из файла несколько раз.

Во всяком случае, вот пример того, как вы могли бы использовать генератор для этой проблемы:

def file_records():
    with open('test.txt', 'r', encoding='UTF-16') as fileHandle:
        for line in fileHandle:
            fields = line.split('[||]')
            therow = {
                'dea_reg_nbr':fields[0],
                'bus_actvty_cd':fields[1],
                'drug_schd':fields[3],
                #50 more columns like this
            }
            yield therow

for record in file_records():
    # do work on one record

Функция file_records является функцией генератора из-за yield ключевое слово. Когда эта функция вызывается, она возвращает итератор, который вы можете перебирать точно так же, как список. records будут возвращены в порядке, и каждый будет словарь.

Если вы не знакомы с генераторами, это хорошее место, чтобы начать читать о них.

То, что делает эту шкалу настолько хорошо, что у вас будет только один therow в памяти одновременно. По сути, происходит то, что в начале каждой итерации цикла file_records Функция читает следующую строку файла и возвращает вычисленную запись. Он будет ждать до тех пор, пока не понадобится следующая строка, прежде чем выполнять работу, и предыдущая запись не останется в памяти, если в ней нет необходимости (например, если на нее есть ссылка в любой структуре данных, которую вы строите # do work on one record).

Обратите внимание, что я переместил open позвонить with заявление. Это обеспечит закрытие файла и освобождение всех связанных ресурсов после выполнения итерации или возникновения исключения. Это гораздо проще, чем пытаться поймать все эти случаи самостоятельно и звонить fileHandle.close(),

Другие вопросы по тегам