Как получить индекс элемента в реагенте

Когда я перебираю вектор в Reagent, вот так:

(for [item ["rattata" "pidgey" "spearow"]]
  [:li item])])

Я хотел бы получить индекс определенного элемента - например:

  [:li item index]

Я не спрашиваю об общем clojure for, потому что меня удовлетворит и другой способ перебора вектора.


person Oskar Skuteli    schedule 07.08.2016    source источник
comment
map-indexed или map по двум коллекциям, одна из которых является диапазоном   -  person Chris Murphy    schedule 08.08.2016
comment
Спасибо. Итак, есть ли причина использовать «для» в этом типе сценария? карта кажется более лаконичной: (map child-component-function collection) по сравнению с: (for [item collection] (child-component-function item))   -  person Oskar Skuteli    schedule 08.08.2016


Ответы (3)


На самом деле это общий вопрос Clojure, а не специфичный для Reagent, но есть несколько способов сделать это.

Вы можете подойти к нему аналогично вашему текущему коду с чем-то вроде

(def items ["rattata" "pidgey" "spearow"])
(for [index (range (count items))]
  [:li (get items index) index])

Вы также можете использовать map-indexed

(doall (map-indexed (fn [index item] [:li index item]) items))

doall в данном случае предназначен для Реагента, поскольку map и друзья возвращают ленивые списки, которые могут мешать Реагент (он выведет предупреждение на консоль, если вы его забудете).

person Walton Hoops    schedule 08.08.2016
comment
Я спрашиваю о Реагенте, потому что все итерации в примерах на их странице используют «для». На самом деле я бы нашел их более читаемыми с «картой» или «индексированной картой», и это работает, поэтому мне интересно, почему они «для». Все еще очень новичок в Clojure, и я боюсь, что что-то здесь упускаю. - person Oskar Skuteli; 08.08.2016
comment
После некоторого исследования: с индексацией по карте все в порядке, но не создает экземпляр реактивного компонента и не позволяет разыменовывать атомы внутри функции. При использовании с doall позволяет разыменовывать атом, но не создает компонент. for это путь, думал, что это должно быть [index (диапазон (количество элементов))] - person Oskar Skuteli; 22.09.2016
comment
Еще один хороший вариант — (map-indexed (fn [index item] ^{:key index}[component index item]) items) - person Oskar Skuteli; 22.09.2016

Вы также можете комбинировать map-indexed с for-loop:

(for [[index item] (map-indexed vector items)]
  [:li item index])])

; vector function is a shorthand:
(for [[index item] (map-indexed (fn [index item] [index item]) items)]
  [:li item index])])
person Simon Perepelitsa    schedule 23.01.2017

Вы можете побаловать себя макросом for-indexed:

(defmacro for-indexed [[item index coll] & body]
  `(for [i# (range (count ~coll))] 
     (let [~item (nth ~coll i#)
           ~index i#]
       ~@body)))
  
(for-indexed [item index ["rattata" "pidgey" "spearow"]]
  [:li item index])

;; => ([:li "rattata" 0] [:li "pidgey" 1] [:li "spearow" 2])

В качестве альтернативы, не передавайте index в привязке и пусть for-indexed возвращает [index item] векторов, например:

(defmacro for-indexed [[item coll] & body]
  `(for [i# (range (count ~coll))] 
     (let [~item [i# (nth ~coll i#)]]
       ~@body)))

(for-indexed [item ["rattata" "pidgey" "spearow"]]
  [:li item])

;; => ([:li [0 "rattata"]] [:li [1 "pidgey"]] [:li [2 "spearow"]])
person Kolja    schedule 19.08.2020