This is 4clojure question #132. The problem statement is: "Write a function that takes a two-argument predicate, a value, and a collection; and returns a new collection where the value is inserted between every two items that satisfy the predicate.".
I came up with the following solution:
(fn [pred value coll]
(let [pairs (seq (zipmap coll (concat (rest coll) [0])))]
(mapcat #(if (apply pred %) [(first %) value] [(first %)]) pairs)))
The first unit test on the site fails, whereas it passes locally on my machine. I'll reproduce the test here:
(= '(1 :less 6 :less 7 4 3) (____ < :less [1 6 7 4 3]))
My question is, what am I doing wrong? Is there some restriction that the site puts on solutions that I'm not adhering to? Or some other issue?
4clojure uses clojure version 1.4, and you are likely using 1.8 or 1.9 alpha. There is a difference in the ordering of the result of zipmap, and this is the reason they are different.
;; 1.9 alpha 15:
(zipmap [1 2 3 4 5] [6 7 8 9 10])
=> {1 6, 2 7, 3 8, 4 9, 5 10}
;; 1.4:
(zipmap [1 2 3 4 5] [6 7 8 9 10])
=> {5 10, 4 9, 3 8, 2 7, 1 6}
Your solution happens to work on a more recent version of clojure, but you are relying on the ordering of a map when you use zipmap, and this is incorrect. The order of k-v pairs in a map is undefined, so your solution is only working by chance as you've currently implemented it.
Your solution will fail anyway if you're given an infinite sequence to process. Consider a different approach where you build the sequence as you walk it.
Good luck!
Related
I am still trying to understand better how to work with transducers in clojure. Here, I am interested in applying aggregating transducers, such as the ones in https://github.com/cgrand/xforms, but reporting at each step the intermediate values of the computation.
For instance, the following expression
(sequence (x/into #{}) [1 2 3])
yields (#{1 2 3}), which is only the final value of the reduction. Now, I would be interested in an transducer xf-incremental that given something like
(sequence (comp xf-incremental (x/into #{})) [1 2 3])
yields (#{1} #{1 2} #{1 2 3}).
The reason why I am interested in this is that I want to report intermediate values of a metric that aggregates over the history of processed values.
Any idea how can I do something of the sort in a generic way?
EDIT: Think of (x/into #{}) as an arbitrary transducer that aggregates results. Better examples could be x/avg or (x/reduce +) where I would expect
(sequence (comp xf-incremental x/avg) [1 2 3])
(sequence (comp xf-incremental (x/reduce +)) [1 2 3])
to return (1 3/2 2) and (1 3 6) respectively.
EDIT 2: another way of phrasing this is that I want a transducer that performs a reducing function and returns the accumulator at each step, which also can reuse all the available transducers so I do not need to rewrite basic functionalities.
Solution using clojure.core/reductions
You don't need a transducer to perform the computation that you are asking for. The function you are looking for to see all the intermediate results of reduce is called reductions and you provide it with conj and an empty set as arguments:
(rest (reductions conj #{} [1 2 3]))
;; => (#{1} #{1 2} #{1 3 2})
rest removes the first empty set, because that was the output you requested in the original question.
The function that builds up the result here is conj, lets refer to it as a step function. A transducer is a function that takes a step function as input and returns a new step function as output. So if we want to combine reductions with a transducer, we can just apply the transducer to conj:
(def my-transducer (comp (filter odd?)
(take 4)))
(dedupe (reductions (my-transducer conj) #{} (range)))
;; => (#{} #{1} #{1 3} #{1 3 5} #{7 1 3 5})
dedupe is there just to remove elements that are equal to preceding elements. You can remove it if you don't want to do that. In that case you get the following, because that is how the filtering transducer works:
(reductions (my-transducer conj) #{} (range)))
;; => (#{} #{} #{1} #{1} #{1 3} #{1 3} #{1 3 5} #{1 3 5} #{7 1 3 5})
Transducer-based solution using net.cgrand.xforms/reductions
Apparently, there is also a transducer version of reductions in the xforms library, which is closer to your initial code:
(require '[net.cgrand.xforms :as xforms])
(rest (sequence (xforms/reductions conj #{}) [1 2 3]))
;; => (#{1} #{1 2} #{1 3 2})
This xforms/reductions transducer can be composed with other transducer using comp to for example filter odd numbers and taking the first four of them:
(sequence (comp (filter odd?)
(take 4)
(xforms/reductions conj #{}))
(range))
;; => (#{} #{1} #{1 3} #{1 3 5} #{7 1 3 5})
In this case, you don't need dedupe. It is also possible to use other step functions with xforms/reductions, e.g. +:
(sequence (comp (filter odd?)
(take 10)
(xforms/reductions + 0)
(filter #(< 7 %)))
(range))
;; => (9 16 25 36 49 64 81 100)
Clojure assoc applied to vector seems have inconsistent behaviour
When index is present in vector, assoc replace the value
(assoc [1 2 3 4 5] 3 42) => [1 2 3 42 5]
When index is next to last one, the vector grows (conj equivalent)
(assoc [1 2 3 4 5] 5 42) => [1 2 3 4 5 42])
Otherwise IndexOutOfBoundsExcpetion is thrown
though it useful in some cases like reduce assoc, this may lead to subtle bugs in a program
Is it expected behaviour or probably bug in assoc for vector?
It is expected. See the docstring for assoc, especially the last note regarding the index argument.
This is described at the top of p. 101 of Clojure Programming.
Let's say I have a data structure like so:
[[1 2 3] [4 5 6] [[7 8 9] [10 11 12]]]
And what I want to end up with is:
[[1 2 3] [4 5 6] [7 8 9] [10 11 12]]
Is there any function that does this automatically?
Basically I'm converting/transforming a SQL result set to CSV, and there are some rows that will transform to 2 rows in the CSV. So my map function in the normal case returns a vector, but sometimes returns a vector of vectors. Clojure.data.csv needs a list of vectors only, so I need to flatten out the rows that got pivoted.
Mapcat is useful for mapping where each element can expand into 0 or more output elements, like this:
(mapcat #(if (vector? (first %)) % [%]) data)
Though I'm not sure if (vector? (first %)) is a sufficient test for your data.
A different approach using tree-seq:
(def a [[1 2 3] [4 5 6] [[7 8 9] [10 11 12]]])
(filter (comp not vector? first)
(tree-seq (comp vector? first) seq a))
I am stretching to use tree-seq here. Would someone with more experience care to comment on if there is a better way to return only the children other than using what is effectively a filter of (not branch?)
Clojure: Semi-Flattening a nested Sequence answers your question, but I don't want to mark this question as a duplicate of that one, since you're really asking a different question than he was; I wonder if it's possible to move his answer over here.
For example
(map #(+ 10 %1) [ 1 3 5 7 ])
Will add 10 to everything
Suppose I want to map everything to the constant 1. I have tried
(map #(1) [ 1 3 5 7 ])
But I don't understand the compiler error.
(map #(1) [ 1 3 5 7 ])
Won't work for two reasons:
#(1) is a zero-argument anonymous function, so it won't work with map (which requires a one-argument function when used with one input sequence).
Even if it had the right arity, it wouldn't work because it is trying to call the constant 1 as a function like (1) - try (#(1)) for example if you want to see this error.
Here are some alternatives that will work:
; use an anonymous function with one (ignored) argument
(map (fn [_] 1) [1 3 5 7])
; a hack with do that ignores the % argument
(map #(do % 1) [1 3 5 7])
; use a for list comprehension instead
(for [x [1 3 5 7]] 1)
; use constantly from clojure.core
(map (constantly 1) [1 3 5 7])
Of the above, I think the versions using constantly or for should be preferred - these are clearer and more idiomatic.
The anonymous function #(+ 10 %1) is equivalent to:
(fn [%1]
(+ 10 %1))
Whereas #(1) is equivalent to:
(fn []
(1))
And trying to call 1 as a function with no args just won't work.
I got this from clojure.org
by googling the words "clojure constant function" as I am just beginning to look at clojure
(map (constantly 9) [1 2 3])
cheers
Is there a 'proper' way to iterate over a two-dimensional sequence in Clojure?
Suppose I had a list of lists of numbers, like this
((1 2 3)
(4 5 6)
(7 8 9))
and I wanted to generate a new list of lists with each number incremented by one. Is there an easy way to do this in Clojure without relying on nested maps or loop/recurs? I've been able to do it, but my solutions are ugly and I find them difficult to understand when I re-read them.
Thanks
What you describe is precisely what clojure.walk is for:
(def matrix [[1 2 3]
[4 5 6]
[7 8 9]])
(use 'clojure.walk :only [prewalk])
(prewalk #(if (number? %) (inc %) %) matrix)
=> [[2 3 4] [5 6 7] [8 9 10]]
Note 1: it is idiomatic to use vectors instead of parentheses for literal sequential collections.
Note 2: walk preserves type.
You can always just use a list comprehension. I find myself using them quite often coming from an imperative background so I don't know how idiomatic it is. In your specific case, you can do:
(for [my-list my-matrix] (map inc my-list))
For the two-dimensional case, you could do something like:
(map #(map inc %) my-two-d-list)
That's not too bad to read: apply the function #(map inc %) to each element in a list.
For the higher-order case, you're basically talking about tree-traversal. You'd want a function that takes in a tree and a function, and applies that function to each node in the tree. You can find functions for this in clojure.walk.
The other answers by Sean and Matt both show concise and effective ways of getting the right result.
However there are some important extensions you can make to this:
It would be nice to handle the case of higher dimensions
It is good to wrap the functionality in a higher order function
Example code:
;; general higher order function
(defn map-dimensions [n f coll]
(if (= n 1)
(map f coll)
(map #(map-dimensions (dec n) f %) coll)))
;; use partial application to specialise to 2 dimensions
(def map-2d (partial map-dimensions 2))
(map-2d inc
'((1 2 3)
(4 5 6)
(7 8 9)))
=> ((2 3 4) (5 6 7) (8 9 10))
Since the introduction of core.matrix in 2013, this is now a much better way of handling operations over multi-dimensional arrays:
(use 'clojure.core.matrix)
(def M [[1 2 3]
[4 5 6]
[7 8 9]])
(emap inc M)
=> [[2 3 4 ]
[5 6 7 ]
[8 9 10]]
Advantages of using core.matrix:
Clean, idiomatic Clojure code
Lots of general purpose n-dimensional array manipulation functions - transpose, shape, reshape, slice, subarray etc.
Ability to plug in high performance array implementations (e.g. for big numerical arrays)
A belated answer, and maybe not exactly what is needed: you could try flatten. It will return a seq that you can iterate over:
(flatten '((1 2 3)
(4 5 6)
(7 8 9)))
user=> (1 2 3 4 5 6 7 8 9)
And in order to increment matrix elements and reassemble the matrix:
(partition 3 (map inc (flatten '((1 2 3)
(4 5 6)
(7 8 9)))))