Clojure: эффективно транспонировать список карт среднего размера - PullRequest
2 голосов
/ 21 ноября 2011

Мне нужен очень быстрый и эффективный способ «транспонировать» список карт в clojure.

Допустим, у меня есть:

(def monthly-sales [{:month 1 :pc "A" :sales 100} 
 {:month 2 :pc "B" :sales 200} ... {:month 12 :pc "Z" :sales 100}])

Мне нужно что-то вроде:

 |PC|1|2|3|4|5|6|7|8|9|10|11|12|
 |A|100||||||||||||
 |Etc.|

Я отвечу на вопрос ниже:

 (let [grouped (group-by (apply juxt [:month]) monthly-sales)]
       (apply str (interpose "\n" 
     (for [k (distinct (map :pc rows))] 
           (str "|" k "|" (clojure.string/join "|" 
         (for [n (range 1 13)]
               (get (first (filter #(= (:pc %) k) (get grouped [n]))) :sale))))))))))))

По сути, я сгруппировал все значения по месяцам (сгруппировал, обратите внимание, что он может быть набран более чем на 1 клавишу благодаря «apply juxt»), это ключ для столбца. Сделав это, я экстраполирую уникальные значения pc, это будет ключ для строки. Отдых должен быть самоочевидным.

Как вы думаете, это ясный клочурский дизайн? Это может быть более эффективным и понятным?

Полезные ссылки: http://pramode.net/clojure/2010/06/01/lazy-sequences-in-clojure/

Ответы [ 2 ]

3 голосов
/ 22 ноября 2011

Идиоматические библиотеки clojure (такие как clojure.java.jdbc) будут предоставлять эти длинные списки в виде отложенных последовательностей. Это означает, что вам просто нужно достаточно памяти, чтобы содержать одну строку плюс обычные накладные расходы на загрузку clojure и библиотек - при условии, что вы получаете данные из файла или базы данных и записываете их в поток / db / что угодно, а не сохраняете их все в память.

Что касается запрашиваемого преобразования, учитывая последовательность строк (отображений), называемых набором результатов, что-то вроде:

(interpose "\n"
  (map (fn [row]
    (clojure.string/join "|" (map row [:consumer :product ...]))
    result-set)))

Даст вам ленивый seq, который вы можете просто скопировать в файл, чтобы получить что-то вроде | отдельные данные, которые вы хотите.

Приложение: что касается «быстрого» - если ваши настройки хранилища не являются необычными, это, вероятно, будет значительно быстрее, чем ваш ввод / вывод хранилища - и это прямо вперед.

0 голосов
/ 22 ноября 2011

Ничто в этом посте не говорит о конечной цели, которую вы хотите достичь, обрабатывая этот набор данных.По крайней мере, я не думаю, что основной идеей может быть помещение 1 ГБ данных в таблицу HTML.Как таковая, никакая информация не может быть дана, как это лучше всего достигнуто.Простая перестановка одних и тех же данных не даст никаких значимых результатов или изменит требования к памяти или доступу для операций, которые вы хотите выполнить впоследствии.

Начнем с того, что то, что вы показываете как «базовые» данные, выглядит так, как будто это могут быть результаты объединенного запроса по крайней мере в трех реляционных таблицах (если они правильно нормализованы).Возможно, гораздо эффективнее получать информацию непосредственно из этих таблиц с помощью SQL, уже сокращая объем информации, фильтруя или сортируя ее перед обработкой в ​​самом Clojure.

Если это не так, надлежащим образом нормализуйте данные и сохраните ихв базе данных может быть вариант, но все зависит от того, что вы хотите сделать с данными в конце.

...