LionelGoulet
LionelGoulet

Reputation: 577

How do I compute a list intersection in Clojure?

I need a function that takes two lists, e.g. (1 2 3 4) and (2 3 4 5), and returns their intersection, i.e. (2 3 4). I wrote up a function that works but it's 8 lines long and very "un-Clojurelike," owing to my newness to the sport. I know there's something elegant out there, hell, maybe even a Clojure keyword that solves the whole problem. The comparison needs to only be at the top level, not recursing through the entire list structures. Thank you in advance.

Upvotes: 3

Views: 859

Answers (3)

LionelGoulet
LionelGoulet

Reputation: 577

As soon as I posted my question, I took another stab at it, and came up with this in a day:

(defmacro FindAtomInList [A L] `(first (drop-while #(not= ~A %) ~L)))   ;; If Atom A is in List L, return it, otherwise, nil.
(defn Intersect [L1 L2] (filter some? (map #(FindAtomInList % L1) L2))) ;; Return the intersection of Lists 1 and 2. Empty if none.

Thank you for your help. The repl is an amazing development tool. I like the idea of a library for set operation. I should have guessed there was such a thing.

Upvotes: 0

Alan Thompson
Alan Thompson

Reputation: 29958

Besides the standard answer above, if for some reason you need to retain the original order you could use a technique like this:

(ns tst.demo.core
  (:use tupelo.core tupelo.test))

(let [a       [1 2 3 4]
      b       [3 4 5]
      result  (filterv (set a) b) ]
  (is= result [3 4]))

based on my favorite template project. Please see also the list of documentation, especially the Clojure CheatSheet.

Upvotes: 2

Shawn Zhang
Shawn Zhang

Reputation: 1852

There is built-in library for set operation if you don't mind the sequence of result set.

(require '[clojure.set :as set])
(set/intersection (set '(1 2 3 4) ) (set '( 3 4 5)))   ; ==> returns #{4 3}

Upvotes: 6

Related Questions