Тест, содержит ли список определенное значение в Clojure

Что состоит в том, чтобы протестировать лучший способ, содержит ли список данное значение в Clojure?

В частности, поведение contains? в настоящее время смущает меня:

(contains? '(100 101 102) 101) => false

Я мог, очевидно, записать простую функцию, чтобы пересечь список и протестировать на равенство, но должен, конечно, быть стандартный способ сделать это?

153
задан Micah Elliott 19 February 2017 в 20:52
поделиться

4 ответа

А, contains?... предположительно, один из пяти самых часто задаваемых вопросов по Clojure.

Он не проверяет, содержит ли коллекция значение; он проверяет, можно ли получить элемент с помощью get или, другими словами, содержит ли коллекция ключ. Это имеет смысл для множеств (которые можно считать не делающими различий между ключами и значениями), карт (поэтому (contains? {:foo 1} :foo) является true) и векторов (но обратите внимание, что (contains? [:foo :bar] 0) является true, поскольку ключами здесь являются индексы, а рассматриваемый вектор действительно "содержит" индекс 0!

Чтобы добавить путаницы, в случаях, когда не имеет смысла вызывать contains?, он просто возвращает false; так происходит в (contains? :foo 1) а также (contains? '(100 101 102) 101). Обновление: В Clojure ≥ 1.5 contains? бросается при передаче объекта типа, который не поддерживает предполагаемую проверку "принадлежности ключа".

Правильный способ сделать то, что вы пытаетесь сделать, следующий:

; most of the time this works
(some #{101} '(100 101 102))

При поиске одного из множества элементов можно использовать большее множество; при поиске false / nil можно использовать false? / nil? -- потому что (#{x} x) возвращает x, поэтому (#{nil} nil) является nil; при поиске одного из нескольких элементов, некоторые из которых могут быть false или nil, вы можете использовать

(some (zipmap [...the items...] (repeat true)) the-collection)

(Обратите внимание, что элементы могут быть переданы в zipmap в любом типе коллекции. )

197
ответ дан 23 November 2019 в 22:03
поделиться

Если уж на то пошло, вот моя простая реализация функции contains для списков:

(defn list-contains? [coll value]
  (let [s (seq coll)]
    (if s
      (if (= (first s) value) true (recur (rest s) value))
      false)))
7
ответ дан 23 November 2019 в 22:03
поделиться

Вот быстрая функция из моих стандартных утилит, которые я использую для этой цели:

(defn seq-contains?
  "Determine whether a sequence contains a given item"
  [sequence item]
  (if (empty? sequence)
    false
    (reduce #(or %1 %2) (map #(= %1 item) sequence))))
5
ответ дан 23 November 2019 в 22:03
поделиться

Вот моя стандартная утилита для той же цели:

(defn in? 
  "true if coll contains elm"
  [coll elm]  
  (some #(= elm %) coll))
123
ответ дан 23 November 2019 в 22:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: