How to remove outer collection from a collection of collections? - clojure

How can I transform '((1 2 3) (4 5 6)) into '(1 2 3) '(4 5 6)?
Concretely, if I have the following collection:
(def coll '((1 2 3) (4 5 6))
And I want to pass both '(1 2 3) and '(4 5 6) as arguments to a method, how can coll be transformed into two lists?
For example, in
(map list ?? coll)
what implementation of ?? would lead to
'((1 4) (2 5) (3 6))
Which is the result of (map list '(1 2 3) '(4 5 6)).
What I tried is:
(flatten coll) does not work since it leads to one list (1 2 3 4 5 6).
Unquote splicing as in ~#coll leads to
Attempting to call unbound fn: #'clojure.core/unquote-splicing.
And mapping with quote as in (map #(quote %) coll) leads to something like (p1__10109# p1__10109#).

The operation is often called transpose. In clojure, you can do it thus:
(apply map list coll) ;((1 4) (2 5) (3 6))

Related

transpose a list of lists clojure [duplicate]

This question already has answers here:
Matrix transposition in clojure
(2 answers)
Closed 6 years ago.
I have a transpose function that works for fixed arities
(defn transpose [a b c]
(map list a b c))
(transpose '(1 2 3) '(4 5 6) '(7 8 9))
((1 4 7) (2 5 8) (3 6 9))
(apply transpose (list '(1 2 3) '(4 5 6) '(7 8 9)))
((1 4 7) (2 5 8) (3 6 9))
But how can I generalise this for n arguments so I could call it as follows:
(transpose '(1 2) '(4 5))
(transpose '(1 2 3) '(4 5 6) '(7 8 9))
...
I feel as thought I need something like the following
(defn transpose [& xs]
(apply (map list) xs))
But I can't get it to work.
You are so close:
(defn transpose [& xs]
(apply map list xs))

In clojure, why doesn't "some" function work consistently on collections?

For below, why does the last one return a nil? Function "some" doesn't work on list of lists?
(some #(= % 1) '(1 3) ) ; ==> true
(some #(= % '(1 3)) ['(1 3) '(1 2 3)] ) ; ==> true
(some #(= % '(1 3)) '('(1 3) '(1 2 3)) ) ;==> nil
You should modify the expression like this:
(some #(= % '(1 3)) '((1 3) (1 2 3)) )
=> true
You already quoted the list by using ', you don't need to quote again in the quoted list.
You can easily check what happened in REPL:
user=> '((1 3) (1 2 3))
((1 3) (1 2 3))
user=> '('(1 3) '(1 2 3))
((quote (1 3)) (quote (1 2 3)))
#Kevin
I see #ntalbs answered but I am in the habit of testing various timings. You may be curious to note the time difference I observed:
(time (some #{'(1 3)} '((1 3) (1 2 3)))) ;0.073
(time (some #(= % '(1 3)) '((1 3) (1 2 3)))) ;0.632
(time (nil? (some #{'(1 3)} '((1 3) (1 2 3))))) ;0.068
(time (nil? (some #(= % '(1 3)) '((1 3) (1 2 3))))) ;0.628
If you are processing large amounts of data this may be a useful knowledge
As ntalbs points out, the issue here is double quoting. It may be a better idea to use vectors instead of lists, or build lists with list. Both would save you some confusion and vectors have different performance characteristics (near constant random access time).
(some #(= % '(1 3)) [[1 3] [1 2 3]])
(some #(= % '(1 3)) (list (list 1 3) (list 1 2 3)))

Append a list to a sequence of lists

I have a sequence of lists:
(def s '((1 2) (3 4) (5 6)))
And I want to append another list to the tail of this sequence, i.e.
(concat-list s '(7 8))
=> '((1 2) (3 4) (5 6) (7 8))
Various approaches that (obviously) don't work:
(cons '((1 2)) '(3 4))
=> (((1 2)) 3 4)
(conj '(3 4) '((1 2)))
=> (((1 2)) 3 4)
(concat '((1 2)) '(3 4))
=> ((1 2) 3 4)
;; close, but wrong order...
(conj '((1 2)) '(3 4))
=> ((3 4) (1 2))
;; Note: vectors work - do I really have to convert entire
;; structure from lists to vectors and back again?
(conj [[1 2]] [3 4])
=> [[1 2] [3 4]]
What are some possible implementations of concat-list, or does there exist library function that does this?
If you find this collection is usually growing to the right, then you should start it off as a vector and keep it that way.That will be the most efficient and convenient.
However, if this collection mostly grows to the left and only rarely to the right, concat is probably your best option:
(concat '((1 2)) ['(3 4)])
Note that concat returns a lazy sequence, not a persistent list.
If the collection is large and grows frequently on both ends, you may want a more advanced collection type like a finger tree or a flexvec.
There may be a better solution, but here's one way:
user=> s
((1 2) (3 4) (5 6))
user=> s2
(7 8)
user=> (concat s (cons s2 '()))
((1 2) (3 4) (5 6) (7 8))

How does this function which reverses the interleave process into x number of subsequences

I completed exercise 43 on 4clojure the other day and checked some of the other solutions. One in particular has confused me.
The challenge asks you to write a function which satisfies all of these:
(= (__ [1 2 3 4 5 6] 2) '((1 3 5) (2 4 6)))
(= (__ (range 9) 3) '((0 3 6) (1 4 7) (2 5 8)))
(= (__ (range 10) 5) '((0 5) (1 6) (2 7) (3 8) (4 9)))
My solution was this:
(fn [l n]
(map #(map second %) (vals (group-by #(mod (first %) n)
(map vector (iterate inc 0) l)))))
User himself had this solution:
#(apply map list (partition %2 %1))
and I couldn't work out how it worked.
Let's work through the first problem:
(= (__ [1 2 3 4 5 6] 2) '((1 3 5) (2 4 6)))
well the (#(partition %2 %1) [1 2 3 4 5 6] 2) would give us ((1 2) (3 4) (5 6)) now how does apply map list on that produce (1 3 5) (2 4 6)
apply is using the ((1 2) (3 4) (5 6)) as a variable length list of additional arguments. Then iteration of the map is applying the list function to all three of these additional lists.
As a result it expands as follows:
(apply map list '((1 2) (3 4) (5 6)))
=> (map list '(1 2) '(3 4) '(5 6))
=> (list 1 3 5) and (list 2 4 6)

Is there an equivalent for the Zip function in Clojure Core or Contrib?

In Clojure, I want to combine two lists to give a list of pairs,
> (zip '(1 2 3) '(4 5 6))
((1 4) (2 5) (3 6))
In Haskell or Ruby the function is called zip. Implementing it is not difficult, but I wanted to make sure I wasn't missing a function in Core or Contrib.
There is a zip namespace in Core, but it is described as providing access to the Zipper functional technique, which does not appear to be what I am after.
Is there an equivalent function for combining 2 or more lists, in this way, in Core?
If there is not, is it because there is an idiomatic approach that renders the function unneeded?
(map vector '(1 2 3) '(4 5 6))
does what you want:
=> ([1 4] [2 5] [3 6])
Haskell needs a collection of zipWith (zipWith3, zipWith4, ...) functions, because they all need to be of a specific type; in particular, the number of input lists they accept needs to be fixed. (The zip, zip2, zip3, ... family can be regarded as a specialisation of the zipWith family for the common use case of tupling).
In contrast, Clojure and other Lisps have good support for variable arity functions; map is one of them and can be used for "tupling" in a manner similar to Haskell's
zipWith (\x y -> (x, y))
The idiomatic way to build a "tuple" in Clojure is to construct a short vector, as displayed above.
(Just for completeness, note that Haskell with some basic extensions does allow variable arity functions; using them requires a good understanding of the language, though, and the vanilla Haskell 98 probably doesn't support them at all, thus fixed arity functions are preferrable for the standard library.)
(partition 2 (interleave '(1 2 3) '(4 5 6)))
=> ((1 4) (2 5) (3 6))
or more generally
(defn zip [& colls]
(partition (count colls) (apply interleave colls)))
(zip '( 1 2 3) '(4 5 6)) ;=> ((1 4) (2 5) (3 6))
(zip '( 1 2 3) '(4 5 6) '(2 4 8)) ;=> ((1 4 2) (2 5 4) (3 6 8))
(map vector [1 2 3] [4 5 6])
to give you exactly what you wanted, mapping list across the two lists will give you a list of lists like in your example. I think that many Clojurians would tend to use vectors for this though it will work with anything. and the inputs do not need to be the same type. map creates seqs from them and then maps the seqs so any seq'able input will work fine.
(map list '(1 2 3) '(4 5 6))
(map list [1 2 3] '(4 5 6))
(map hash-map '(1 2 3) '(4 5 6))
(map hash-set '(1 2 3) '(4 5 6))
The built-in way would simply be the function 'interleave':
(interleave [1 2 3 4] [5 6 7 8]) => [1 5 2 6 3 7 4 8]
There is a function called zipmap, that may have the similar effect,
(zipmap (1 2 3)(4 5 6))
The ouput is as fllows:
{3 6, 2 5, 1 4}
#(apply map list %) transposes a matrix just like the Python zip* function. As a macro definition:
user=> (defmacro py-zip [lst] `(apply map list ~lst))
#'user/py-zip
user=> (py-zip '((1 2 3 4) (9 9 9 9) (5 6 7 8)))
((1 9 5) (2 9 6) (3 9 7) (4 9 8))
user=> (py-zip '((1 9 5) (2 9 6) (3 9 7) (4 9 8)))
((1 2 3 4) (9 9 9 9) (5 6 7 8))