Подтвердить что ты не робот

Clojure: вызывать функцию для каждого элемента в векторе с индексом

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

(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?

4b9b3361

Ответ 1

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

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

Я бы воспользовался вашей версией, если только не было причин, почему бы и нет.

Ответ 2

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

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

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

Ответ 3

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

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

Ответ 4

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

(doseq [[idx val] (indexed ["Hello" "World" "Test" "This"])]
  (setCell 0 idx val))

Ответ 5

Я сделал небольшое сравнение производительности опций sofar:

; 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 suggestion
(def total 0.0)
(time (doall (map #(testThis %1 %2) (iterate inc 0) testD)))
(println "Total: " total)

; time using Brian 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

Предварительное заключение:

Используйте решение loop/recur.