2014-10-12 2 views
1

У меня большой CSV, который не будет полностью вписываться в память, и мне нужно много работать над этим. Я новичок в ленивых последовательностях, не знаю, как это решить. Я пытаюсь прочитать весь файл в памяти, а затем проанализировать его, я знаю, что это неправильно.Двойное чтение большого файла CSV

Вот что я пытаюсь сделать:

  1. Прочитайте строку заголовка и делать вещи, основываясь на этом. Он используется во всей программе.
  2. Прочитать все строки и собрать сводные данные по каждому столбцу.
  3. Используйте сводные данные для преобразования исходных данных и записи нового файла.

Есть ли способ прочитать в строке заголовка и использовать его постоянно, не приводя к проблеме «держаться за голову» с ленивыми последовательностями, сохраняя все это в памяти?

Я нашел это связанный нить: using clojure-csv.core to parse a huge csv file

+0

Разбирает файл дважды, строку за строкой. На первом проходе собирайте сводную информацию; на втором проходе выполните ваши преобразования и напишите результаты в новый файл, строчно. –

+0

Могу ли я определить два разных символа с 'let' или повторно использовать один и тот же? Почему это не позволяет «держаться за голову»? – user1559027

+0

Пожалуйста, посмотрите, переводит ли мой вариант вопроса на предложение, задавая вопрос о возможности конкретного результата, переводит этот пост из «преимущественно основанного на мнениях». – user1559027

ответ

2

Clojure заботится о расчистке локальных привязок, так как только не обязательный больше не будет использоваться, будет обнулена, чтобы сделать его elegible для GC. Так что ваш код может выглядеть примерно так:

(defn gather-summary [file] 
    (with-open [rdr (io/reader file)] 
     (let [lines (csv/read-csv rdr) 
      header (first lines)] 
      (reduce (fn [so-far row] 
        (if header 
        (inc so-far) 
        (dec so-far))) 
       0 
       (rest lines)))) 

(defn modify [summary file] 
    ;similar to gather 
    ) 

(defn process [file] 
    (let [summary (gather-summary file)] 
     (modify summary file))) 

header не держит голову, потому что он просто имеет первый элемент, который не имеет никакого реф к остальной части линий.

lines не используется после вызова (rest lines) fn, поэтому Clojure очистит его.

reduce работа по рекурсивному способу, так Clojure также берет на not holding the head in that case

+0

Рассмотрите возможность использования 'binding' вместо' var', потому что 'var' - это определенный тип данных в Clojure, который является изменяемым и почти всегда глобальным. – noisesmith

+0

Спасибо! Изменено. – DanLebrero

+0

Итак, ключом к этому решению является инкапсуляция файла, считывающего внутри функции с помощью файла? Таким образом, когда функция возвращается, она знает, чтобы освободить базовую последовательность? Я объявлял последовательность файлов в одной и той же области 'let' и передавал ее всем функциям в качестве аргумента, но это похоже на мой главный недостаток дизайна. – user1559027

Смежные вопросы