2013-12-06 2 views
3

Я хотел бы написать функцию, которая проверяет, является ли карта подмножеством другого.Как проверить, является ли карта подмножеством другого в clojure?

Пример использования должно быть:

(map-subset? {:a 1 :b 2} {:a 1 :b 2 :c 3}) 
=> true 

Есть ли собственный способ сделать это?

+1

Какое определение отношения подмножества вы говорите? Подмножество на клавишах и одинаковые значения? – kasterma

ответ

1

сделать предположение о том, что вы имеете в виду подмножество (прямой перевод этого определения):

(and (every? (set (keys m1)) (keys m2)) ;; subset on keys 
    (every? #(= (m1 %)(m2 %)) (keys m2))) ;; on that subset all the same values 
+0

извините, по подмножеству я хотел сказать, подмап, спасибо – szymanowski

1

Существует множество возможных путей решения вашего вопроса. Одним из возможных возможных решений могло бы стать:

(defn contains-submap? [map-structure keys] 
    (every? (partial contains? map-structure) keys)) 

(contains-submap? {:a 1 :b 2 :c 3} (keys {:a 1 :b 2})) 
true 

Это может быть сделано с помощью наборов, например. Но, как указал @kasterma, это зависит от вашего первоначального намерения.

8
(defn submap? 
    "Checks whether m contains all entries in sub." 
    [^java.util.Map m ^java.util.Map sub] 
    (.containsAll (.entrySet m) (.entrySet sub))) 

REPL демо:

(submap? {:foo 1 :bar 2 :quux 3} {:foo 1 :bar 2}) 
;= true 
(submap? {:foo 1 :bar 2 :quux 3} {:foo 1 :bar 3}) 
;= false 
(submap? {:foo 1 :bar 2} {:foo 1 :bar 2 :quux 3}) 
;= false 
+0

Предпочтительны ли в этом случае подсказки типа? Если да, скажите, пожалуйста, почему? – Chiron

+0

@Chiron Потому что без них все три вызова метода будут отражающими, и функция будет ужасно медленной. С добавлением типов подсказок я ожидал бы, что это будет одним из самых быстрых решений. –

9

Путем преобразования карты в наборы, вы можете использование clojure.set/subset?

(clojure.set/subset? (set {:a 1 :b 2}) (set {:a 1 :b 2 :c 3})) 
=> true 

Это сделает каждую пару карты элемент в наборе

(set {:a 1 :b 2 :c 3}) 
=> #{[:b 2] [:c 3] [:a 1]} 

И как таковые, {:a 1 :b 3} не будет подмножеством

(clojure.set/subset? (set {:a 1 :b 3}) (set {:a 1 :b 2 :c 3})) 
=> false 
3

Другим вариантом может быть:

(defn submap? [a b] 
    (= a (select-keys b (keys a)))) 

Это проверяет справедливость ключей на первой карте.

0

Предполагая, что вы собираетесь ключи и значения соответствуют ...

Есть ли собственный способ сделать это?

Нет стандартной функции. Я предлагаю ...

(defn map-subset? [a-map b-map] 
    (every? (fn [[k _ :as entry]] (= entry (find b-map k))) a-map)) 

Несколько примеров:

(map-subset? {:a 1 :b 2} {:a 1 :b 2 :c 3}) 
=> true 

(map-subset? {:d 4} {:a 1 :b 2 :c 3}) 
=> false 

(map-subset? {:a 3} {:a 1 :b 2 :c 3}) 
=> false 

(map-subset? {:a nil} {}) 
=> false 
  • Он проходит свой первый аргумент только один раз.
  • Он правильно обрабатывает значения nil.

Если ни одно из них не важно, используйте более элегантную версию, например, kasterma's.

Смежные вопросы