I am trying to map a function that takes two arguments to a vector.
For example, given a vector [2, 3, 4], I'd like to add 2 to every digits by "+" function.
Here is what I tried :
(map (defn add2[i] (+ 2 i)) [2, 3, 4])
(map (+ 2) [2, 3, 4])
Anonymous functions are declared with fn or #() :
(map (fn [i] (+ 2 i)) [2 3 4])
(map #(+ 2 %) [2 3 4])
You could also use partial :
(map (partial + 2) [2 3 4])
Commas are optional and usually not used in source code.
You want to use the anonymous function fn
$ (map (fn [x] (+ 2 x)) [2 3 4])
=> [4 5 6]
#(do %1 %2) is reader sugar for fn
$ (map #(+ %) [2 3 4]);the first argument can be either % or %1
=> [4 5 6]
or alternatively you can use partial to return a function that partially applies the function you give it to one of the arguments. You should prefer this one for partial application of constant values.
$ (map (partial + 2) [2 3 4]);the first argument can be either % or %1
=> [4 5 6]
(map (fn [i] (+ 2 i)) [1 2 3])
Or instead use the following anonymous function :#(+ 2 %)
You can also do:(partial + 2) to define a partial function
Your second code example won't work because you need to tell clojure where to put the argument that map is applying the function to. The way to do this is to either define a function (as you've done in your first example) or to create an anonymous function as I've done above.
Related
I'm writing a clojure function like:
(defn area [n locs]
(let [a1 (first locs)]
(vrp (rest locs))))
I basically want to input like: (area 3 '([1 2] [3 5] [3 1] [4 2])) But when I do that it gives me an error saying Wrong number of args (1) passed. But I'm passing two arguments.
What I actually want to do with this function is that whatever value of n is inputted (say 3 is inputted), then a1 should store [1 2], a2 should store [3 5], a3 should store ([3 1] [4 2]). What should I add in the function to get that?
clojue's build in split-at function is very close to solving this. It splits a sequence "at" a given point. So if we first split the data apart and then wrap the second half in a list and concatenate it back together again it should solve this problem:
user> (let [[start & end] (split-at 2 sample-data)]
(concat start end))
([1 2] [3 5] ([3 1] [4 2]))
the & before end in let causes the last item to be rolled up in a list. It's equivalent to:
user> (let [[start end] (split-at 2 sample-data)]
(concat start (list end)))
([1 2] [3 5] ([3 1] [4 2]))
If I recklessly assume you have some function called vrp that needs data in this form then you could finish your function with something like this:
(defn area [n locs]
(let [[start end] (split-at (dec n) sample-data)
a (concat start (list end))]
(apply vrp a)))
Though please forgive me to making wild guesses as to the nature of vrp, I could be totally off base here.
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)
When I pass this function
(into []
(map #(+ %1 %2)
[1 2]
[5 6]))
I get this result: [6 8]
What should I do to get this: [6 7 7 8] while keeping this #(+ %1 %2) ?
Seems like map isn't the right function in this case.
Use for when you want a Cartesian product:
user=> (for [x [1 2] y [5 6]]
#_=> (+ x y))
(6 7 7 8)
for is one option as Alex answer shows. map can also be used (with mapcat) as shown below:
user=> (mapcat #(map (partial + %1) [5 6]) [1 2])
(6 7 7 8)
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)
I have a list with embedded lists of vectors, which looks like:
(([1 2]) ([3 4] [5 6]) ([7 8]))
Which I know is not ideal to work with. I'd like to flatten this to ([1 2] [3 4] [5 6] [7 8]).
flatten doesn't work: it gives me (1 2 3 4 5 6 7 8).
How do I do this? I figure I need to create a new list based on the contents of each list item, not the items, and it's this part I can't find out how to do from the docs.
If you only want to flatten it one level you can use concat
(apply concat '(([1 2]) ([3 4] [5 6]) ([7 8])))
=> ([1 2] [3 4] [5 6] [7 8])
To turn a list-of-lists into a single list containing the elements of every sub-list, you want apply concat as nickik suggests.
However, there's usually a better solution: don't produce the list-of-lists to begin with! For example, let's imagine you have a function called get-names-for which takes a symbol and returns a list of all the cool things you could call that symbol:
(get-names-for '+) => (plus add cross junction)
If you want to get all the names for some list of symbols, you might try
(map get-names-for '[+ /])
=> ((plus add cross junction) (slash divide stroke))
But this leads to the problem you were having. You could glue them together with an apply concat, but better would be to use mapcat instead of map to begin with:
(mapcat get-names-for '[+ /])
=> (plus add cross junction slash divide stroke)
The code for flatten is fairly short:
(defn flatten
[x]
(filter (complement sequential?)
(rest (tree-seq sequential? seq x))))
It uses tree-seq to walk through the data structure and return a sequence of the atoms. Since we want all the bottom-level sequences, we could modify it like this:
(defn almost-flatten
[x]
(filter #(and (sequential? %) (not-any? sequential? %))
(rest (tree-seq #(and (sequential? %) (some sequential? %)) seq x))))
so we return all the sequences that don't contain sequences.
Also you may found useful this general 1 level flatten function I found on clojuremvc:
(defn flatten-1
"Flattens only the first level of a given sequence, e.g. [[1 2][3]] becomes
[1 2 3], but [[1 [2]] [3]] becomes [1 [2] 3]."
[seq]
(if (or (not (seqable? seq)) (nil? seq))
seq ; if seq is nil or not a sequence, don't do anything
(loop [acc [] [elt & others] seq]
(if (nil? elt) acc
(recur
(if (seqable? elt)
(apply conj acc elt) ; if elt is a sequence, add each element of elt
(conj acc elt)) ; if elt is not a sequence, add elt itself
others)))))
Example:
(flatten-1 (([1 2]) ([3 4] [5 6]) ([7 8])))
=>[[1 2] [3 4] [5 6] [7 8]]
concat exampe surely do job for you, but this flatten-1 is also allowing non seq elements inside a collection:
(flatten-1 '(1 2 ([3 4] [5 6]) ([7 8])))
=>[1 2 [3 4] [5 6] [7 8]]
;whereas
(apply concat '(1 2 ([3 4] [5 6]) ([7 8])))
=> java.lang.IllegalArgumentException:
Don't know how to create ISeq from: java.lang.Integer
Here's a function that will flatten down to the sequence level, regardless of uneven nesting:
(fn flt [s] (mapcat #(if (every? coll? %) (flt %) (list %)) s))
So if your original sequence was:
'(([1 2]) (([3 4]) ((([5 6])))) ([7 8]))
You'd still get the same result:
([1 2] [3 4] [5 6] [7 8])