clojure core.logic counting elements in a set - clojure

I try to do something like this in core.logic
(defn count-different-elements-in-list [coll]
(count (set coll)))
this works with integers just fine
(should= 1 (count-different-elements-in-list '(1 1 1)))
(should= 2 (count-different-elements-in-list '(1 1 2)))
(should= 3 (count-different-elements-in-list '(1 3 2)))
but now I'm trying to use core.logic to solve some stuff and there it get's messy
(run* [a b c]
;;the variables get values between 1 and 3
(fd/in a b c (fd/interval 1 3))
;; in the list there should only be 2 different values
(== 2 (count-different-elements-in-list '(a b c))))
but here comes the problem, a b c don't get passed as values to the function. They get passed as variables. With three variables count-different-elements-in-list returns always 3 and core.logic doesn't find a solution (empty list).
But I'm looking for this result.
([1 1 2] [1 2 1] [2 1 1]
[1 1 3] [1 3 1] [3 1 1]
[2 2 1] [2 1 2] [1 2 2]
[2 2 3] [2 3 2] [3 2 2]
[3 3 1] [3 1 3] [1 3 3]
[3 3 2] [3 2 3] [2 3 3])

You need to core.logic/project logic vars into non-relational goals, like the normal function count-different-elements-in-list. Unfortunately, you cannot project finite domain logic vars, like a, b, and c, that are not constrained to a single value. (See: this question)
In the example you have, you can swap out the fd/in and fd/interval for a generated range and membero. This would remove the unconstrained finite domain vars, keep the range constraint for integers, and allow for projection.
(def interval (vec (range 1 4)))
(run* [a b c]
(membero a interval)
(membero b interval)
(membero c interval)
(project [a b c]
(== 2 (count-different-elements-in-list (list a b c)))))

Related

Split vector after each occurance of an element

This should be easy but I'm finding it more difficult than expected.
Given [0 1 2 0 1 2 0 1], split the sequence after each occurance of 2.
Result should be similar to [[0 1 2] [0 1 2] [0 1]].
split functions only split at the first instance. My imagination is also limited on how to use the partition functions to achieve this.
previous solutions are ok (although #magos solution if flawed in some cases), but if this function is to be used as an utility (it is rather general i guess), i would use the classic iterative approach:
(defn group-loop [delim coll]
(loop [res [] curr [] coll (seq coll)]
(if coll
(let [group (conj curr (first coll))]
(if (= delim (first coll))
(recur (conj res group) [] (next coll))
(recur res group (next coll))))
(if (seq curr)
(conj res curr)
res))))
in repl:
user> (map (partial group-loop 2)
[[]
nil
[1 2 3 1 2 3]
[1 2 3 1 2 3 2]
[2 1 2 3 1 2 3]
[1 3 4 1 3 4]])
;;([] []
;; [[1 2] [3 1 2] [3]]
;; [[1 2] [3 1 2] [3 2]]
;; [[2] [1 2] [3 1 2] [3]]
;; [[1 3 4 1 3 4]])
Though it looks a bit too verbose, it still has some rather important advantages: first of all it is kind of classic (which i find a pro rather than con), second: it is fast (according to my benchmark about 3 times faster than reduce variant, and 6 to 10 times faster than partition variant)
also you can make it more clojurish with some minor tweaks, returning lazy collection as clojure's sequence operating functions do:
(defn group-lazy [delim coll]
(loop [curr [] coll coll]
(if (seq coll)
(let [curr (conj curr (first coll))]
(if (= delim (first coll))
(cons curr (lazy-seq (group-lazy delim (rest coll))))
(recur curr (next coll))))
(when (seq curr) [curr]))))
user> (map (partial group-lazy 2)
[[]
nil
[1 2 3 1 2 3]
[1 2 3 1 2 3 2]
[2 1 2 3 1 2 3]
[1 3 4 1 3 4]])
;;(nil nil
;; ([1 2] [3 1 2] [3])
;; ([1 2] [3 1 2] [3 2])
;; ([2] [1 2] [3 1 2] [3])
;; [[1 3 4 1 3 4]])
Here's one way by combining two partition variants. First use partition-by to divide at instances of 2, then take two and two of those partitions with partition-all and join them together using concat.
(->> [0 1 2 0 1 2 0 1]
(partition-by (partial = 2)) ;;((0 1) (2) (0 1) (2) (0 1))
(partition-all 2) ;;(((0 1) (2)) ((0 1) (2)) ((0 1)))
(mapv (comp vec (partial reduce concat)))) ;;[[0 1 2] [0 1 2] [0 1]]
Although note that if the input starts on a 2 the returned partitions will also start with 2s, not end on them as here.
Here you go, works as requested for all inputs:
(reduce #(let [last-v (peek %1)]
(if (= 2 (last last-v))
(conj %1 [%2])
(conj (pop %1) (conj last-v %2))))
[[]]
[2 2 0 1 2 3 4 2 2 0 1 2 2])
=> [[2] [2] [0 1 2] [3 4 2] [2] [0 1 2] [2]]
While Magos has an elegant solution, it is unfortunately not complete, as he mentions. So, the above should do the job using reduce.
We look at the most recently added element. If it was a 2, we create a new sub-vector ((conj %1 [%2])). Otherwise, we add it to the last sub-vector. Pretty simple really. Existing functions like the partitions and splits are great for reusing when possible, but sometimes the best solution is a custom function, and in this case it's actually pretty clean.

Clojure: how to test if a seq is a "subseq" of another seq

Is there an easy / idiomatic way in Clojure to test whether a given sequence is included within another sequence? Something like:
(subseq? [4 5 6] (range 10)) ;=> true
(subseq? [4 6 5] (range 10)) ;=> false
(subseq? "hound" "greyhound") ;=> true
(where subseq? is a theoretical function that would do what I'm describing)
It seems that there is no such function in the core or other Clojure libraries... assuming that's true, is there a relatively simple way to implement such a function?
(defn subseq? [a b]
(some #{a} (partition (count a) 1 b)))
(defn subseq? [target source]
(pos? (java.util.Collections/indexOfSubList (seq source) (seq target))))
***
DISCLAIMER EDIT
This proposal is not reliable for reasons discussed in comments section.
***
#amalloy 's solution has one flaw - it won't work with infinite lazy sequences. So it will loop forever when you run this:
(subseq? [1 2 3] (cycle [2 3 1]))
I propose this implementation to fix this:
(defn- safe-b
"In case b is a cycle, take only two full cycles -1 of a-count
to prevent infinite loops yet still guarantee finding potential solution."
[b a-count]
(take
(* 2 a-count)
b))
(defn subseq? [a b]
(let [a-count (count a)]
(some #{a} (partition a-count 1 (safe-b b a-count)))))
=> #'user/safe-b
=> #'user/subseq?
(subseq? [1 2 3] (cycle [2 3 1]))
=> [1 2 3]
(subseq? [1 2 3] (cycle [3 2 1]))
=> nil
(subseq? [1 2 3] [2 3])
=> nil
(subseq? [2 3] [1 2 3])
=> [2 3]

why does the output of core.logic give the same value repeated?

I tried this in core.logic
(require [clojure.core.logic :as l])
(l/run* [q]
(l/fresh [a b c]
(l/membero a [1])
(l/membero b [4 5])
(l/membero c [1 2])
(l/== q [a b])))
expecting the result to be [1 4] [1 5]
but it was [1 4] [1 4] [1 5] [1 5]
then I started playing with it and found this:
(require [clojure.core.logic :as l])
(l/run* [q]
(l/fresh [a b c]
(l/membero a [1])
(l/membero b [4 5])
(l/membero c [1 1 1 1 1 1 1 1])
(l/== q [a b])))
;; => ([1 4] [1 4] [1 4] [1 5] [1 4] [1 4] [1 5] [1 4] [1 5] [1 4] [1 5] [1 5] [1 5] [1 5])
where there is a [1 5] interspersed with [1 4]
what is happening? is this repetition thing supposed to be a feature or a bug?
This is because the usage of the logic variable c which is not required as it is not being unified with q. If you remove c then you will get desired result. Basically you need to understand how the substitution works in core.logic to understand why you are getting these duplicate results because of c.
At a high level the process is like searching a tree for solutions, in this case each element in the vector which is membero with c leads to a node in the search tree and that causes duplicate results because for each node introduced by c probable values leads to correct result as c isn't used in the unification (l/== q [a b])

Puzzled: Clojure for loop with :while -> unexpected behaviour?

I've been learning Clojure and puzzled by the following:
user=> (for [a (range 1 4) b (range 1 4)] [a b])
([1 1] [1 2] [1 3] [2 1] [2 2] [2 3] [3 1] [3 2] [3 3]); _no surprise here_
Let's add :while (not= a b), I expect to see an empty list as the loop should stop if the condition is false. In this case it's the very first item where a=b=1. Let's see:
user=> (for [a (range 1 4) b (range 1 4) :while (not= a b) ] [a b])
([2 1] [3 1] [3 2]) ; _surprise!_
Changing :while to :when to filter out (= a b) pairs
user=> (for [a (range 1 4) b (range 1 4) :when (not= a b) ] [a b])
([1 2] [1 3] [2 1] [2 3] [3 1] [3 2]); _expected_
Could anyone explain why (for [ ... :while ..] ...) behaves like this?
I'm using Clojure 1.3 on OS X.
Thank you and apologize for the lack of formatting. This is my virgin post on StackOverflow.
Let's look at each iteration.
a = 1
b = 1 -> a == b, break because of while
a = 2
b = 1 -> a != b, print [2 1]
b = 2 -> a == b, break because of while
a = 3
b = 1 -> a != b, print [3 1]
b = 2 -> a != b, print [3 2]
b = 3 -> a == b, break because of while
The :while condition in for only terminates the inner-most loop. I use for all the time, but :while so rarely that I never realized this; thanks for the great question!
Sadly I think the best you can do is wrap a take-while around the for, since you want a "global" stop-counter on the output sequence, not a stop-counter on one of the input sequences you're iterating over. For example:
(->> (for [a (range 1 4)
b (range 1 4)]
[a b])
(take-while (fn [[a b]] (not= a b))))
()

Compare two vectors in clojure no matter the order of the items

I want to compare two vectors and find out if the items they have are the same no matter the order the items are in.
So..
right now in clojure:
(= [1 2 3] [3 2 1]) ;=> false
I want:
(other_fun [1 2 3] [3 2 1]) ;=> true
(other_fun [1 2 3 4] [3 2 1]) ;=> false
I could not find a containsAll like in java
If you do care about duplicates, you can compare their frequency maps. These are maps with each collection element as a key and number of occurrences as a value. You create them using standard function frequencies, like in given examples.
Different order, same number of duplicates:
(= (frequencies [1 1 2 3 4])(frequencies [4 1 1 2 3]))
evaluates true.
Different order, different number of duplicates:
(= (frequencies [1 1 2 3 4])(frequencies [4 1 2 3]))
evaluates false.
So, you can write a function:
(defn other_fun [& colls]
(apply = (map frequencies colls)))
If you don't care about duplicates, you could create sets from both vectors and compare these:
(= (set [1 2 3]) (set [3 2 1])) ;=> true
As a function:
(defn set= [& vectors] (apply = (map set vectors)))
If you don't care about duplicates, other answers a perfectly applicable and efficient.
But if you do care about duplicates, probably the easiest way to compare two vectors is sorting and comparing:
user=> (= (sort [3 5 2 2]) (sort [2 2 5 3]))
true
user=> (= (sort [3 5 2 2]) (sort [2 5 3]))
false
Create sets from them:
user=> (= (set [1 2 3]) (set [3 2 1]))
true
user=> (defn other_func [col1 col2]
(= (set col1) (set col2)))
#'user/other_func
user=> (other_func [1 2 3] [3 2 1])
true
You're on the JVM already, so if you want containsAll, then just use containsAll, right?
(defn other_fun
"checkes the presence of the elements of vec1 in vec2 and vice versa"
[vec1 vec2]
(if (or (some nil?
(for [a vec1 b [vec2]] (some #(= % a) b)))
(some nil?
(for [a vec2 b [vec1]] (some #(= % a) b))))
false
true))
(other_fun [1 2 3] [3 2 1]) ;=> true
(other_fun [1 2 3 4] [3 2 1]) ;=> false