You could do something like this:
(defn seq-xor-2-seqs
"Returns the unique values that are in one sequence but not the
other."
[x y]
(let [x (into #{} x)
y (into #{} y)]
(lazy-cat (clojure.set/difference x y)
(clojure.set/difference y x))))
Not sure this is more idiomatic, though. And I guess it would perform
worse with huge collections...
Stuart
Thanks, that's a nice alternative approach!
Bill
On Mon, Oct 27, 2008 at 11:12 AM, Stuart Halloway
<stuart....@gmail.com> wrote:
>
> You could do something like this:
>
> (defn seq-xor-2-seqs
> "Returns the unique values that are in one sequence but not the
> other."
> [x y]
> (let [x (into #{} x)
> y (into #{} y)]
> (lazy-cat (clojure.set/difference x y)
> (clojure.set/difference y x))))
>
> Not sure this is more idiomatic, though. And I guess it would perform
> worse with huge collections...
If I'm reading thing's correctly, Bill's solution is O(n^2), while
Stuart's is O(n*log(n)) or better. It looks like difference iterates
over one seq and for each item does a lookup (nearly constant time) on
the the other, although copying into sets may use more memory.
By the way, difference is eager, so I'm not sure there's much point in
using lazy-cat. :-)
Here's another approach to do all the seqs at once:
(defn seq-xor
"Returns unique values that are in one sequence but not the others."
[& seqs]
(let [obj-cnt (reduce (fn [acc s]
(merge-with + acc (into {} (for [i s] {i 1}))))
{} seqs)]
(for [[obj cnt] obj-cnt :when (== cnt 1)]
obj)))
--Chouser
On Mon, Oct 27, 2008 at 8:46 AM, Chouser <cho...@gmail.com> wrote:
>
> I think it's generally better to use = instead of .equals for
> equality, unless you have a specific reason to not use = (which I
> don't think is the case here).
Only that it allowed me to talk about Java interop in my blog post. ;-)
Oooh, very nice!
Thanks,
Bill
I think I am missing something here, can you elaborate?
> By the way, difference is eager, so I'm not sure there's much point in
> using lazy-cat. :-)
I am using lazy-cat *because* difference is eager. Is that mistaken?
For example, the first expression below returns immediately, and the
second does not.
(take 1 (lazy-cat [1 2] [(Thread/sleep 10000)]))
(1)
user=> (lazy-cat [1 2] [(Thread/sleep 10000)])
(1 2 nil)
Stuart
Hm, no, you've got a good point. I guess I didn't put much thought
into that statement.
I guess I was thinking that in order to return anything at all, your
function already copied both seqs into sets and ran difference once,
and so holding off on the second run of difference wasn't worth much.
But I guess that may be an inaccurate assumption. Also, I try to be
careful to use lazy outer functions when using lazy inner functions,
in order to prevent an outer eager function from destroying the
laziness of the inner -- but I was wrong in jumping to the conclusion
eager inner funcs suggest the use of eager outer funcs.
On the other hand by using lazy-cat, the returned object is going to
keep references to both full set objects, so that the difference can
be computed later. Using an eager concat would allow the larger sets
to be gc'ed.
Though upon examination of boot.clj, it looks like "concat" is lazy
also. And now I'm wondering what the difference is between concat and
lazy-cat.
So anyway, you're right -- lazy-cat may make sense with eager inner
funcs in general and in this case in particular.
--Chouser
Yet another clever alternative!
Thanks guys!
- Bill
Excellent summarization! I've updated my blog post with the examples
and used your comment as the 'closer' for the blog post.
> Thanks so much for the blog series!
Thank you. I'm having lots of fun with Clojure!
- Bill