In Clojure is there an easy way to convert between list types?

Clojure

Clojure Problem Overview


I am often finding myself using a lazy list when I want a vector, and vice versa. Also, sometimes I have a vector of maps, when I really wanted a set of maps. Are there any helper functions to help me to convert between these types?

Clojure Solutions


Solution 1 - Clojure

Let's not forget that trusty old into lets you take anything seqable (list, vector, map, set, sorted-map) and an empty container you want filled, and puts it into it.

(into [] '(1 2 3 4)) ==> [1 2 3 4]         "have a lazy list and want a vector"
(into #{} [1 2 3 4]) ==> #{1 2 3 4}        "have a vector and want a set"
(into {} #{[1 2] [3 4]}) ==> {3 4, 1 2}    "have a set of vectors want a map"
(into #{} [{1 2} {3 4}]) ==> #{{1 2} {3 4}} "have a vector of maps want a set of maps"

into is a wrapper around conj, which is the base abstraction for inserting new entries appropriately into a collection based on the type of the collection. The principle that makes this flow so nicely is that Clojure is build on composable abstractions, in this case into on top of conj on top of collection and seq.

The above examples would still compose well if the recipient was being passed in at run time: because the underlying abstractions (seq and conj) are implemented for all the collections (and many of Java's collections also), so the higher abstractions don't need to worry about lots of special data-related corner cases.

Solution 2 - Clojure

vec, set and generally into are your friends to easily "convert" to another collection type.

How do you want to transform a vector of maps into a map of maps? You need a key, can you provide use with sample input/expected output?

Solution 3 - Clojure

For vectors there is the vec function

user=> (vec '(1 2 3))
[1 2 3]

For lazy sequences there is the lazy-seq function

user=> (lazy-seq [1 2 3])
(1 2 3)

For converting into sets, there is the set function

user=> (set [{:a :b, :c :d} {:a :b} {:a :b}])
#{{:a :b} {:a :b, :c :d}}

Solution 4 - Clojure

One more answer for converting from a list to a map (for the sake of completeness) - from here:

(apply hash-map '(1 2 3 4))
;=>{1 2, 3 4}

Solution 5 - Clojure

To convert a vector to a list you can also use for, like this:

=> (for [i [1 2 3 4]] i)
(1 2 3 4)

When you don't want to manipulate the data, just use seq on the vector:

=> (seq [1 2 3])
(1 2 3)

Solution 6 - Clojure

There is no need to convert a vector to a list. Clojure will treat a vector as it would treat a list - as a sequence - when a sequence is required. For example,

user=> (cons 0 [1 2 3])
(0 1 2 3)

If you need to make sure that the vector is being treated as a sequence, wrap it in seq:

user=> (conj [1 2 3] 0) ; treated as a vector
[1 2 3 0]

user=> (conj (seq [1 2 3]) 0) ; treated as a sequence
(0 1 2 3)

If you have a vector of maps, and you want a set of maps, it doesn't matter that the vector holds maps. You just convert the vector to a set as usual:

user=> (set [{:a 1, :b 2} {"three" 3, "four" 4}])
#{{:a 1, :b 2} {"four" 4, "three" 3}}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionyazz.comView Question on Stackoverflow
Solution 1 - ClojureArthur UlfeldtView Answer on Stackoverflow
Solution 2 - ClojurecgrandView Answer on Stackoverflow
Solution 3 - ClojurecobbalView Answer on Stackoverflow
Solution 4 - ClojurehawkeyeView Answer on Stackoverflow
Solution 5 - ClojureGeert-Jan HutView Answer on Stackoverflow
Solution 6 - ClojureThumbnailView Answer on Stackoverflow