Clojure: вызов функции для каждого элемента вектора с индексом - PullRequest
26 голосов
/ 30 октября 2009

Скажите, у меня есть вектор:

(def data ["Hello" "World" "Test" "This"])

И я хочу заполнить таблицу где-нибудь с API:

(defn setCell
  [row col value]
  (some code here))

Тогда как лучше всего выполнить следующие вызовы:

(setCell 0 0 "Hello")
(setCell 0 1 "World")
(setCell 0 2 "Test")
(setCell 0 3 "This")

Я обнаружил, что будет работать следующее:

(let [idv (map vector (iterate inc 0) data)]
  (doseq [[index value] idv] (setCell 0 index value)))

Но есть ли более быстрый способ, который не требует новой временной структуры данных idv?

Ответы [ 5 ]

27 голосов
/ 13 мая 2011

Немного опоздал в игре, но для людей, получающих доступ к этой странице: теперь (начиная с clojure 1.2) в clojure.core доступна функция map-indexed.

Одна проблема (если я не ошибаюсь): нет эквивалента "pmap", что означает, что вычисления с индексированием карты не могут быть легко распараллелены. В этом случае я бы сослался на решения, предложенные выше.

27 голосов
/ 30 октября 2009

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

(map #(setCell 0 %1 %2) (iterate inc 0) data)

Вы можете заключить это в (doall или (doseq, чтобы звонки происходили сейчас. Очень хорошо отобразить бесконечный seq вместе с конечным, потому что map остановится, когда закончится самый короткий seq.

10 голосов
/ 30 октября 2009

То, как вы это делаете, идиоматично (и фактически идентично clojure.contrib.seq-utils/indexed). Если вы действительно хотите избежать дополнительной структуры данных, вы можете сделать это:

(loop [data data, index 0]
  (when (seq data)
    (setCell 0 index (first data))
    (recur (rest data) (inc index))))

Я бы использовал вашу версию, если бы не было веской причины не делать этого.

8 голосов
/ 31 октября 2009

Самый лучший способ - использовать clojure.contrib.seq-utils/indexed, который будет выглядеть следующим образом (с использованием деструктуризации):

(doseq [[idx val] (indexed ["Hello" "World" "Test" "This"])]
  (setCell 0 idx val))
1 голос
/ 30 октября 2009

Я сделал краткое сравнение производительности опций софар:

; just some function that sums stuff 
(defn testThis
  [i value]
 (def total (+ total i value)))

; our test dataset. Make it non-lazy with doall    
(def testD (doall (range 100000)))

; time using Arthur's suggestion
(def total 0.0)
(time (doall (map #(testThis %1 %2) (iterate inc 0) testD)))
(println "Total: " total)

; time using Brian's recursive version
(def total 0.0)
(time (loop [d testD i 0]
  (when (seq d)
    (testThis i (first d))
    (recur (rest d) (inc i)))))
(println "Total: " total)

; with the idiomatic indexed version
(def total 0.0)
(time (let [idv (map vector (iterate inc 0) testD)]
  (doseq [[i value] idv] (testThis i value))))
(println "Total: " total)

Результаты на моем 1-ядерном ноутбуке:

   "Elapsed time: 598.224635 msecs"
   Total:  9.9999E9
   "Elapsed time: 241.573161 msecs"
   Total:  9.9999E9
   "Elapsed time: 959.050662 msecs"
   Total:  9.9999E9

Предварительный вывод:

Используйте решение для цикла / повторения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...