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

#clojure

Вопрос:

Мне очень нравится использовать contains? , потому что это так кратко и читабельно. Я хочу посмотреть, содержит ли набор карт, которые имеют те же пары ключей и значений, что и пример, в котором также были другие пары значений ключей. Я почти уверен contains? , что здесь это не сработает. Есть ли альтернатива? Может быть, мне придется его написать (я наконец-то вхожу в образ мышления!). Например, если бы у меня был

 (def some-set #{{:foo "bar" :beep "boop"}{:foo "bar"} {:foo "bar" :hi "there"}})
 

каким был бы быстрый способ узнать, есть ли у него какие-либо карты, которые совпадают {:foo "bar" :one "two"} :foo "bar" ?

Ответ №1:

Отредактировано: Помня, что карта представляет собой набор векторов ключ-значение, вот реализация предиката submap? :

 (defn submap?
  "Returns true if subm is a submap of m, false otherwise."
  [subm m]
  (every? (fn [[k v]] (= (get m k ::not-found) v)) subm))
 

Этот предикат можно использовать для фильтрации любой коллекции:

 (filter #(submap? {:a 1 :b 2} %) [{:a 1} {:a 1 :b 2 :c 3}])
=> ({:a 1, :b 2, :c 3})
 

Оригинальный ответ

Это решение работает, но медленнее, чем мой обновленный ответ, из-за построения (set m) для больших m

 (defn submap?
  "Returns true if subm is a submap of m, false otherwise."
  [subm m]
  (let [kvs (set m)]
    (every? kvs subm)))
 

Комментарии:

1. Спасибо вам за это! Я собираюсь попробовать это сейчас.

Ответ №2:

Общим способом было бы написать предикат, который проверяет, содержит ли карта другую карту. Это можно сделать, используя select-keys только карту с определенными ключами; используя keys карту для сравнения, а затем просто сравнивая результат, вы получите это.

 (def maps #{{:foo "bar" :beep "boop"} {:foo "bar"} {:foo "bar" :hi "there"} {:foo "baz"}})

(defn submap?
  [submap m]
  (= (select-keys m (keys submap)) submap))

(println
  (filter (partial submap? {:foo "bar"}) maps))
; → ({:foo bar, :beep boop} {:foo bar, :hi there} {:foo bar})
 

Тем не менее, это всего лишь простой последовательный поиск. Это не означает (и
, к сожалению, в ядре нет ничего, что могло бы помочь), что ваши карты находятся в наборе.
Также обратите внимание, что порядок результата не определен, так как порядок
наборов тоже.

Комментарии:

1. Классно! Раньше я думал, о… боже… Я должен написать это, но теперь я начинаю создавать свои собственные маленькие утилиты (со всей вашей помощью). Я также ценю предложение Алана о библиотеке. Немного того и другого будет ключевым моментом.

Ответ №3:

Вы можете найти множество предикатов такого рода и связанных с ними вспомогательных функций в библиотеке Тупело, в частности:

  • подкапывание?
  • субматч?
  • дикий матч?
  • дикий-субматч?

Это особенно полезно при написании модульных тестов. Например, вас могут интересовать только определенные поля, например :body , при тестировании ответа веб-сервера, и вы хотите игнорировать другие поля, такие как IP-адрес или метка времени.

Модульные тесты показывают код в действии.

Комментарии:

1. Я много видел Тьюпело и собираюсь взглянуть на него сейчас. Спасибо вам также за то, что показали, где я могу видеть, как он используется… очень полезно!