Why does clojure.core/rest output a list when input is a vector? - clojure

Why does clojure.core/rest output a list when input is a vector?
This creates an unexpected effect:
(conj [1 2 3] 4)
; => [1 2 3 4]
(conj (rest [1 2 3]) 4)
; => (4 2 3)
I know that "it calls seq on its argument" from the docs which creates this effect. I don't understand why this is the desired effect. As a naïve user, I would expect (rest [1 2 3]) to behave like (subvec [1 2 3] 1). I know I could just use subvec for my use case. For the sake of learning, I would like to understand the rationale of rest, and use cases where outputting a list is desirable (even when the input is a vector).

The output of rest is NOT a list, but a seq, which is an even lower level abstraction. From the official documentation for rest:
Returns a possibly empty seq of the items after the first. Calls seq on its
argument.
The confusion arises from the fact that both are printed between parens, but if you look closely, they are different:
user=> (list? (rest [1 2 3]))
false
user=> (seq? (rest [1 2 3]))
true
How it's a seq different from a list? seqs are implemented with an Interface that requires implementing first, rest and cons, but details are up to the collection implementation. For instance, vectors use their own implementation:
user=> (class (rest [1 2 3]))
clojure.lang.PersistentVector$ChunkedSeq
user=> (class (rest '(1 2 3)))
clojure.lang.PersistentList
List are an implementation that at least extends a basic Seq interface, and builds on top. For instance, clojure.lang.PersistentList implements the Counted interface which requires a constant-time version of count.
For a detailed description of the differences between Seqs and Lists, check these links:
Differences between a seq and a list
https://clojure.org/reference/sequences

You make a good case for rest on a vector returning a vector. The trouble is that rest is one of the fundamental operations on sequences, and a vector is not a sequence:
=> (seq? [1 2 3 4])
false
However, if rest can accept a seqable thing such as a vector, you could say that it ought to be able to return such.
What does it return?
=> (type (rest [1 2 3 4]))
clojure.lang.PersistentVector$ChunkedSeq
This gives every appearance of being a subvec wrapped in a seq call.

I know that "it calls seq on its argument"
That is correct. Seqs are implemented with an Interface (ISeq) that requires implementing first, rest and cons.
rest takes any Seq'able (any collection that implements ISequable). The reason for using this is efficiency and simplicity.
The way different collection works, the most efficient way of getting the first and rest is different.
Which is why when you convert one collection into a seq, it will come with the most efficient implementation on rest and the others.
I hope this was clear

I agree that this behavior is unexpected and counterintuitive. As a workaround, I created the append and prepend functions in the Tupelo library.
From the docs, we see examples:
Clojure has the cons, conj, and concat functions, but it is not obvious how they should be used to add a new value to the beginning of a vector or list:
; Add to the end
> (concat [1 2] 3) ;=> IllegalArgumentException
> (cons [1 2] 3) ;=> IllegalArgumentException
> (conj [1 2] 3) ;=> [1 2 3]
> (conj [1 2] 3 4) ;=> [1 2 3 4]
> (conj '(1 2) 3) ;=> (3 1 2) ; oops
> (conj '(1 2) 3 4) ;=> (4 3 1 2) ; oops
; Add to the beginning
> (conj 1 [2 3] ) ;=> ClassCastException
> (concat 1 [2 3] ) ;=> IllegalArgumentException
> (cons 1 [2 3] ) ;=> (1 2 3)
> (cons 1 2 [3 4] ) ;=> ArityException
> (cons 1 '(2 3) ) ;=> (1 2 3)
> (cons 1 2 '(3 4) ) ;=> ArityException
Do you know what conj does when you pass it nil instead of a sequence? It silently replaces it with an empty list: (conj nil 5) ⇒ (5) This can cause you to accumulate items in reverse order if you aren’t aware of the default behavior:
(-> nil
(conj 1)
(conj 2)
(conj 3))
;=> (3 2 1)
These failures are irritating and unproductive, and the error messages don’t make it obvious what went wrong. Instead, use the simple prepend and append functions to add new elements to the beginning or end of a sequence, respectively:
(append [1 2] 3 ) ;=> [1 2 3 ]
(append [1 2] 3 4) ;=> [1 2 3 4]
(prepend 3 [2 1]) ;=> [ 3 2 1]
(prepend 4 3 [2 1]) ;=> [4 3 2 1]
Both prepend and append always return a vector result.

Related

Putting singles and lists into a list in clojure

Is there a more elegant way to have into work with single items and lists than the following (admittedly atrocious) function?
(defn into-1-or-more
[this-list list-or-single]
(into this-list (flatten (conj [] list-or-single))))
Which can handle either:
(into-1-or-more [1 2 3 4] 5)
;[1 2 3 4 5]
Or:
(into-1-or-more [1 2 3 4] [5 6 7 8])
;[1 2 3 4 5 6 7 8]
I am building a collection with reduce using into [] with results from functions in a list. However some of the functions return single items, and others return lists of items. Like:
(reduce #(into [] (% data)) [func-return-item func-return-list func-return-either])
Would the best solution be to just do the following instead?
(into [] (flatten (map #(% data) [func-return-item ...])
Although it would be more ideal to know for sure what return type you are getting, here is a simple answer:
(flatten [ curr-list (mystery-fn) ] )
Examples:
(flatten [[1 2 3] 9 ] )
;=> (1 2 3 9)
(flatten [[[1] 2 3] [4 5] 6 ] )
;=> (1 2 3 4 5 6)
You could wrap it into a function if you want, but it hardly seems necessary.
This transducer flattens sequential inputs, but only by one "level":
(defn maybe-cat [rf]
(let [catrf (cat rf)]
(fn
([] (rf))
([result] (rf result))
([result input]
(if (sequential? input)
(catrf result input)
(rf result input))))))
Example:
(into [] maybe-cat [[:foo] :bar [[:quux]]])
;= [:foo :bar [:quux]]
As this example demonstrates, this approach makes it possible to include sequential collections in the output (by wrapping them in an additional sequential layer – [[:quux]] produces [:quux] in the output).

How do I replicate items from a list in Clojure?

I've tried this for so many nights that I've finally given up on myself. Seems like an extremely simple problem, but I guess I'm just not fully understanding Clojure as well as I should be (I partially attribute that to my almost sole experience with imperative languages). The problem is from hackerrank.com
Here is the problem:
Problem Statement
Given a list repeat each element of the list n times. The input and output
portions will be handled automatically by the grader.
Input Format
First line has integer S where S is the number of times you need to repeat
elements. After this there are X lines, each containing an integer. These are the
X elements of the array.
Output Format
Repeat each element of the original list S times. So you have to return
list/vector/array of S*X integers. The relative positions of the values should be
same as the original list provided as input.
Constraints
0<=X<=10
1<=S<=100
So, given:
2
1
2
3
Output:
1
1
2
2
3
3
I've tried:
(fn list-replicate [num list]
(println (reduce
(fn [element seq] (dotimes [n num] (conj seq element)))
[]
list))
)
But that just gives me an exception. I've tried so many other solutions, and this probably isn't one of my better ones, but it was the quickest one I could come up with to post something here.
(defn list-replicate [num list]
(mapcat (partial repeat num) list))
(doseq [x (list-replicate 2 [1 2 3])]
(println x))
;; output:
1
1
2
2
3
3
The previous answer is short and it works, but it is very "compressed" and is not easy for new people to learn. I would do it in a simpler and more obvious way.
First, look at the repeat function:
user=> (doc repeat)
-------------------------
clojure.core/repeat
([x] [n x])
Returns a lazy (infinite!, or length n if supplied) sequence of xs.
user=> (repeat 3 5)
(5 5 5)
So we see how to easily repeat something N times.
What if we run (repeat n ...) on each element of the list?
(def N 2)
(def xvals [1 2 3] )
(for [curr-x xvals]
(repeat N curr-x))
;=> ((1 1) (2 2) (3 3))
So we are getting close, but we have a list-of-lists for output. How to fix? The simplest way is to just use the flatten function:
(flatten
(for [curr-x xvals]
(repeat N curr-x)))
;=> (1 1 2 2 3 3)
Note that both repeat and for are lazy functions, which I prefer to avoid unless I really need them. Also, I usually prefer to store my linear collections in a concrete vector, instead of a generic "seq" type. For these reasons, I include an extra step of forcing the results into a single (eagar) vector for the final product:
(defn list-replicate [num-rep orig-list]
(into []
(flatten
(for [curr-elem xvals]
(repeat N curr-elem)))))
(list-replicate N xvals)
;=> [1 1 2 2 3 3]
I would suggest building onto Alan's solution and instead of flatten use concat as this will preserve the structure of the data in case you have input sth like this [[1 2] [3 4]].
((fn [coll] (apply concat (for [x coll] (repeat 2 x)))) [[1 2] [3 4]])
output: => ([1 2] [1 2] [3 4] [3 4])
unlike with flatten, which does the following
((fn [coll] (flatten (for [x coll] (repeat 2 x)))) [[1 2] [3 4]])
output: => (1 2 1 2 3 4 3 4)
as for simple lists e.g. '(1 2 3), it works the same:
((fn [coll] (apply concat (for [x coll] (repeat 2 x)))) '(1 2 3))
output => (1 1 2 2 3 3)
(reduce #(count (map println (repeat %1 %2))) num list)

Difference between arrow and double arrow macros in Clojure

What is the difference between the -> and ->> macros in Clojure?
The docs A. Webb linked to explain the "what", but don't do a good job of the "why".
As a rule, when a function works on a singular subject, that subject is the first argument (e.g., conj, assoc). When a function works on a sequence subject, that subject is the last argument (e.g., map, filter).
So, -> and ->> are documented as threading the first and last arguments respectively, but it is also useful to think of them as applying to singular or sequential arguments respectively.
For example, we can consider a vector as a singular object:
(-> [1 2 3]
(conj 4) ; (conj [1 2 3] 4)
(conj 5) ; (conj [1 2 3 4] 5)
(assoc 0 0)) ; (assoc [1 2 3 4 5] 0 0)
=> [0 2 3 4 5]
Or we can consider it as a sequence:
(->> [1 2 3]
(map inc) ; (map inc [1 2 3])
(map inc) ; (map inc (2 3 4))
(concat [0 2])) ; (concat [0 2] (3 4 5))
=> (0 2 3 4 5)

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

Standard version or idiomatic use of (fn [f & args] (apply f args))

Every so often I find myself wanting to apply a collection of functions on several collections of parameters. It's easy to do with map and a very simple function.
(map
(fn invoke [f & args] (apply f args))
[- + *]
[1 2 3]
[1 2 3]
[1 2 3])
(-1 6 27)
Searching the web turns up quite a few libraries that define a similar function, often called funcall or invoke. Because of Clojure's penchant for variadic functions, I cannot help but think there should already be a default version of this function.
Is there, or is there another idiomatic way to solve situations like this ?
Edit:
Another form may be
(map
(comp eval list)
[- + *]
[1 2 3]
[1 2 3]
[1 2 3])
(-1 6 27)
Which scares me because of the eval.
If you really don't have a clue about the function name, but you know what the in- and output have to be, you can try https://github.com/Raynes/findfn.
(find-arg [-1 6 27] map '% [- + *] [1 2 3] [1 2 3] [1 2 3])
;=> (clojure.core/trampoline)
This tells us that
(map trampoline [- + *] [1 2 3] [1 2 3] [1 2 3])
;=> (-1 6 27)
Actually, you can abuse trampoline as funcall in clojure. But it is hardly idiomatic, because it is a Lisp-1. The above code evaluates to:
[(trampoline - 1 1 1), (trampoline + 2 2 2), (trampoline * 3 3 3)] which then becomes
[-1 6 27] (in the form a of lazyseq to be precise).
As Adrian Mouat points out in the comment below, this probably isn't the preferred way to solve it. Using a funcall like construct smells a bit funny. There must be a cleaner solution. Until you've found that one, findfn can be helpful ;-).
Edit: this will do what you want (as #BrandonH mentioned):
(map #(apply %1 %&) [- + *] [1 2 3] [1 2 3] [1 2 3])
But this is hardly an improvement over your version -- it just uses a shorthand for anonymous functions.
My understanding is that FUNCALL is necessary in Common Lisp, as it's a Lisp-2, whereas Clojure is a Lisp-1.
There isn't a funcall or equivalent function in the standard Clojure library that works exactly this way. "apply" is pretty close but needs a collection of arguments at the end rather than being purely variadic.
With this in mind, you can "cheat" with apply to make it work as follows by adding an infinite list of nils to the end (which get considered as empty sequences of additional arguments):
(map apply [- + *] [1 2 3] [1 2 3] [1 2 3] (repeat nil))
=> (-1 6 27)
Overall though, I think the sensible approach if you really want to use this function frequently is just to define it:
(defn funcall [f & ps]
(apply f ps))
(map funcall [- + *] [1 2 3] [1 2 3] [1 2 3])
=> (-1 6 27)
(map #(%1 %2 %3 %4) [- + *][1 2 3][1 2 3][1 2 3])
(-1 6 27)
The problem is that if you want to allow a variable number of arguments, the & syntax puts the values in a vector, necessitating the use of apply. Your solution looks fine to me but as Brandon H points out, you can shorten it to #(apply %1 %&).
As the other answerers have noted, it has nothing to do with funcall which I think is used in other Lisps to avoid ambiguity between symbols and functions (note that I called the function as (%1 ...) here, not (funcall %1 ...).
I personally think your first version is pretty clear and idiomatic.
Here's an alternative you might find interesting to consider however:
(map
apply
[- + *]
(map vector [1 2 3] [1 2 3] [1 2 3]))
=> (-1 6 27)
Note the trick of using (map vector ....) to transpose the sequence of arguments into ([1 1 1] [2 2 2] [3 3 3]) so that they can be used in the apply function.
Another approach which is fairly self explanatory: "for each nth function, apply it to all nth elements of the vectors":
(defn my-juxt [fun-vec & val-vecs]
(for [n (range 0 (count fun-vec))]
(apply (fun-vec n) (map #(nth % n) val-vecs))))
user> (my-juxt [- + *] [1 2 3] [1 2 3] [1 2 3])
(-1 6 27)
I can't right now thing of a clojure.core function that you could plug into your map and have it do what you want. So, I'd say, just use your own version.
Matt is probably right that the reason there isn't a funcall, is that you hardly ever need it in a Lisp-1 (meaning, functions and other bindings share the same name space in clojure)
What about this one? It selects the relevant return values from juxt. Since this is all lazy, it should only calculate the elements needed.
user> (defn my-juxt [fns & colls]
(map-indexed (fn [i e] (e i))
(apply map (apply juxt fns) colls)))
#'user/my-juxt
user> (my-juxt [- + *] [1 2 3] [1 2 3] [1 2 3])
(-1 6 27)