Как построить вектор с помощью вызова, чтобы уменьшить
Я пытаюсь понять, почему эта функция не работает должным образом. Из сообщения об ошибке я подозреваю, что это как-то связано с тем, как я создаю пустой вектор для аккумулятора.
У меня есть простая функция, которая возвращает последовательность 2-элементных векторов:
(defn zip-with-index
"Returns a sequence in which each element is of the
form [i c] where i is the index of the element and c
is the element at that index."
[coll]
(map-indexed (fn [i c] [i c]) coll))
Это отлично работает. Проблема возникает, когда я пытаюсь использовать его в другой функции
(defn indexes-satisfying
"Returns a vector containing all indexes of coll that satisfy
the predicate p."
[p coll]
(defn accum-if-satisfies [acc zipped]
(let [idx (first zipped)
elem (second zipped)]
(if (p elem)
(conj acc idx)
(acc))))
(reduce accum-if-satisfies (vector) (zip-with-index coll)))
Он компилируется, но когда я пытаюсь его использовать, я получаю сообщение об ошибке:
user=> (indexes-satisfying (partial > 3) [1 3 5 7])
ArityException Wrong number of args (0) passed to: PersistentVector
clojure.lang.AFn.throwArity (AFn.java:437)
Я не могу понять, что здесь происходит. Также, если есть более "Clojure" способ сделать то, что я пытаюсь сделать, мне интересно услышать об этом тоже.
3 ответа
Проблема, вероятно, в другом предложении accum-if-satisfies
, должно быть просто acc
не (acc)
,
Вы могли бы использовать filter
а потом map
вместо reduce
, Как это:
(map #(first %)
(filter #(p (second %))
(zip-with-index coll)))
Вы также можете позвонить map-indexed
с vector
вместо (fn [i c] [i c])
, Весь код будет выглядеть так:
(defn indexes-satisfying
[p coll]
(map #(first %)
(filter #(p (second %))
(map-indexed vector coll))))
Что касается более Clojure-подобного способа, вы можете использовать
(defn indexes-satisfying [pred coll]
(filterv #(pred (nth coll %))
(range (count coll))))
использование filter
вместо filterv
вернуть ленивый seq, а не вектор.
Кроме того, вы не должны использовать defn
определить внутренние функции; вместо этого он будет определять глобальную функцию в пространстве имен, в которой определена внутренняя функция, и, кроме того, иметь незначительные побочные эффекты. использование letfn
вместо:
(defn outer [& args]
(letfn [(inner [& inner-args] ...)]
(inner ...)))
Еще один способ сделать это будет:
(defn indexes-satisfying [p coll]
(keep-indexed #(if (p %2) % nil) coll))