clojure: permutations of subsets? - clojure

I'm new to clojure, looking for a function to generate permutations of subsets:
=> (find-subsets 1 #{1 2 3 4})
(#{1} #{2} #{3} #{4})
=> (find-subsets 2 #{1 2 3 4})
(#{1 2} #{1 3} #{1 4} #{2 3} #{2 4} #{3 4})
=> (find-subsets 3 #{1 2 3 4})
(#{1 2 3} #{1 3 4} #{2 3 4})
Does such a thing exist? If not, is there a nice, clean, idiomatic way to code the function?

Take a look at combinatorics. It does what you need:
; all the unique ways of taking n different elements from items
(clojure.math.combinatorics/combinations [1 2 3] 2)
;;=> ((1 2) (1 3) (2 3))
If it complains because you use a set instead of a vector, just convert to vector with vec before calling combinations.

Related

Turning this list into a vector of sets

Does anyone have an idea how to convert this list of vectors into a vector of sets?
([#{2}] [#{1 2 3 4}] [#{5}] [#{3}])
result should be
[#{2} #{1 2 3 4} #{5} #{3}]
Multiple ways to accomplish this. It depends on your needs what approach you use:
(def data '([#{2}] [#{1 2 3 4}] [#{5}] [#{3}]))
;; If you have a list of single element lists:
(mapv first data) ;; => [#{2} #{1 2 3 4} #{5} #{3}]
;; If you have a list of multiple element lists:
(vec (apply concat data)) ;; => [#{2} #{1 2 3 4} #{5} #{3}]
;; If you also want to handle multiple levels of nesting:
(vec (flatten data)) ;; => [#{2} #{1 2 3 4} #{5} #{3}]
;; If you ..;
(transduce (map first) conj data) ;; => [#{2} #{1 2 3 4} #{5} #{3}]
A way I haven't seen suggested is using into and cat.
(def data '([#{2}] [#{1 2 3 4}] [#{5}] [#{3}]))
(into [] cat data) => [#{2} #{1 4 3 2} #{5} #{3}]
Note that the sets are just elements of the vectors.
So, one way is to iterate (map) over the list of vectors and pick the first element of each vector (i.e. the set). This will build a list of these sets that you can then convert to a vector:
user=> (vec (map first '([#{2}] [#{1 4 3 2}] [#{5}] [#{3}])))
[#{2} #{1 4 3 2} #{5} #{3}]

How to search and replace in a Clojure script data structure?

I would like to have a search and replace on the values only inside data structures:
(def str [1 2 3
{:a 1
:b 2
1 3}])
and
(subst str 1 2)
to return
[2 2 3 {:a 2, :b 2, 1 3}]
Another example:
(def str2 {[1 2 3] x, {a 1 b 2} y} )
and
(subst str2 1 2)
to return
{[1 2 3] x, {a 1 b 2} y}
Since the 1's are keys in a map they are not replaced
One option is using of postwalk-replace:
user> (def foo [1 2 3
{:a 1
:b 2
1 3}])
;; => #'user/foo
user> (postwalk-replace {1 2} foo)
;; => [2 2 3 {2 3, :b 2, :a 2}]
Although, this method has a downside: it replaces all elements in a structure, not only values. This may be not what you want.
Maybe this will do the trick...
(defn my-replace [smap s]
(letfn [(trns [s]
(map (fn [x]
(if (coll? x)
(my-replace smap x)
(or (smap x) x)))
s))]
(if (map? s)
(zipmap (keys s) (trns (vals s)))
(trns s))))
Works with lists, vectors and maps:
user> (my-replace {1 2} foo)
;; => (2 2 3 {:a 2, :b 2, 1 3})
...Seems to work on arbitrary nested structures too:
user> (my-replace {1 2} [1 2 3 {:a [1 1 1] :b [3 2 1] 1 1}])
;; => (2 2 3 {:a (2 2 2), :b (3 2 2) 1 2})

How do I append a set to a vector?

Let's say I have [{1 2 3 4}]. How do I append {5 6 7 8} so that the vector will say [{1 2 3 4} {5 6 7 8}]
The same way you append any other value to a vector: conj
(let [v [#{1 2 3 4}]]
(conj v #{5 6 7 8}))
;; gives [#{1 2 3 4} #{5 6 7 8}]
(Incidentally, note the #{} syntax. {1 2 3 4} is a map containing the pairs (1 2) and (3 4), while #{1 2 3 4} is a set of the numbers 1, 2, 3 and 4.)
(conj [#{1 2 3 4}] #{5 6 7 8})
Note that in your example you have not sets, but maps from long to long.
Also, note that this is not appending to the vector (vectors are immutable), but rather it is creating a new vector with the new value appended.

Is there a standard func that takes a dict and a list of keys and returns the list of corresponding vals?

I'm looking for something similar to select-keys:
(desired-fn {:a 1, :b 2, :c 3, :d 4} [:a :d])
;= [1 4]
;; N.B. the order of the keys in the argument seq is preserved
(= (desired-fn (array-map :a 1, :b 2, :c 3, :d 4)
[:b :c])
(desired-fn (array-map :d 4, :c 3, :a 1, :b 2)
[:b :c]))
;= true
It's not particularly hard to implement, though I haven't tried to come up with a good name yet:
(defn select-values-corresponding-to-keys [m ks]
(for [k ks]
(get m k)))
Am I ignorant of a standard function that meets precisely this need? If not, do other languages —e.g., Python, Ruby, Haskell— have a name for this function?
Maps are functions which operate on their keys:
({:a 1, :b 2} :a)
;=> 1
(map {:a 1, :b 2, :c 3, :d 4} [:a :d])
;=> (1 4)
(= (map (array-map :a 1, :b 2, :c 3, :d 4)
[:b :c])
(map (array-map :d 4, :c 3, :a 1, :b 2)
[:b :c]))
;=> true
If you want the result as a vector, just use vec or into [] ..., or replace map with mapv.
Keywords are themselves functions (they implement IFn) and they can look themselves into a map and return the value so one option would be to use juxt:
(def keys-to-vals (juxt :b :c))
(= (keys-to-vals {:a 1, :b 2, :c 3, :d 4})
(keys-to-vals {:d 4, :c 3, :a 1, :b 2}))
So basically your desired fn now becomes:
(defn select-vals [map keys] ((apply juxt keys) map))
map is the function you are looking for:
(map {:a 1 :b 2 :c 3} [:a :c])
=> (1 3)
This works because the hashmap itself works as a function (i.e. implements clojure.lang.IFn) that returns the value for any key that it is given.
user=> ((juxt :a :c) {:a 1 :b 2 :c 3})
[1 3]
Jay Fields explores this function and a couple other related ones in an insightful blog post # http://blog.jayfields.com/2011/01/clojure-select-keys-select-values-and.html.
(I found that by accident just a few minutes ago when I searched for "select-keys".)
I'd still like to know if there's a "canonical" implementation somewhere, so I'm leaving the question as open.

Clojure equality of collections with sequences

I noticed that Clojure (1.4) seems to be happy to consider vectors equal to the seq of the same vector, but that the same does not apply for maps:
(= [1 2] (seq [1 2]))
=> true
(= {1 2} (seq {1 2}))
=> false
Why should the behaviour of = be different in this way?
Clojure's = can be thought of as performing its comparisons in two steps:
Check if the types of the things being compared belong to the same "equality partition", that is a class of types whose members might potentially be equal (depending on things like the exact members of a given data structure, but not the particular type in the partition);
If so, check if the things being compared actually are equal.
One such equality partition is that of "sequential" things. Vectors are considered sequential:
(instance? clojure.lang.Sequential [])
;= true
As are seqs of various types:
(instance? clojure.lang.Sequential (seq {1 2}))
;= true
Therefore a vector is considered equal to a seq if (and only if) their corresponding elements are equal.
(Note that (seq {}) produces nil, which is not sequential and compares "not equal" to (), [] etc.)
On the other hand, maps constitute an equality partition of their own, so while a hash map might be considered equal to a sorted map, it will never be considered equal to a seq. In particular, it is not equal to the seq of its entries, which is what (seq some-map) produces.
I guess this is because in sequences order as well as value at particular position matters where as in map the order of key/value doesn't matter and this difference between semantics causes this to work as shown by your sample code.
For more details have a look at mapEquals in file https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/APersistentMap.java
It checks if the other object is not map then return false.
user=> (seq {1 2})
([1 2])
user=> (type {1 2})
clojure.lang.PersistentArrayMap
It seems to me that this example points out a slight inconsistency in the notion of equality of values in clojure for this case where they are different types derived from the same type (by the seq function). It could well be argued that this is not inconsistent because it is comparing a derived type to the type it is derived from and I can understand that if the same logic was applied to this same example using vectors (note at the bottom)
the contents are the same type:
user> (type (first (seq {1 2})))
clojure.lang.MapEntry
user> (type (first {1 2}))
clojure.lang.MapEntry
user> (= (type (first {1 2})) (type (first (seq {1 2}))))
true
user> (= (first {1 2}) (first (seq {1 2})))
true
the sequences have the same values
user> (map = (seq {1 2}) {1 2})
(true)
but they are not considered equal
user> (= {1 2} (seq {1 2}))
false
this is true for longer maps as well:
user> (map = (seq {1 2 3 4}) {1 2 3 4})
(true true)
user> (map = (seq {1 2 3 4 5 6}) {1 2 3 4 5 6})
(true true true)
user> (map = (seq {9 10 1 2 3 4 5 6}) {9 10 1 2 3 4 5 6})
(true true true true)
even if they are not in the same order:
user> (map = (seq {9 10 1 2 3 4 5 6}) {1 2 3 4 5 6 9 10})
(true true true true)
but again not if the containing types differ :-(
user> (= {1 2 3 4} (seq {1 2 3 4}))
false
EDIT: this is not always true see below:
to work around this you can convert everything to a seq before comparison, which is (I presume) safe because the seq function always iterates the whole data structure the same way and the structures are immutable values and a seq of a seq is a seq
user> (= (seq {9 10 1 2 3 4 5 6}) {1 2 3 4 5 6 9 10})
false
user> (= (seq {9 10 1 2 3 4 5 6}) (seq {1 2 3 4 5 6 9 10}))
true
vectors are treated differently:
user> (= [1 2 3 4] (seq [1 2 3 4]))
true
Perhaps understanding the minor inconsistencies is part of learning a language or someday this could be changed (though I would not hold my breath)
EDIT:
I found two maps that produce different sequences for the same value so just calling seq on the maps will not give you proper map equality:
user> (seq (zipmap [3 1 5 9][4 2 6 10]))
([9 10] [5 6] [1 2] [3 4])
user> (seq {9 10 5 6 1 2 3 4})
([1 2] [3 4] [5 6] [9 10])
user>
here is an example of what I'm calling proper map equality:
user> (def a (zipmap [3 1 5 9][4 2 6 10]))
#'user/a
user> (def b {9 10 5 6 1 2 3 4})
#'user/b
user> (every? true? (map #(= (a %) (b %)) (keys a)))
true
(seq some-hash-map) gives you a sequence of entries (key/value pairs).
For example:
foo.core=> (seq {:a 1 :b 2 :c 3})
([:a 1] [:c 3] [:b 2])
which is not the same as [:a 1 :b 2 :c 3].