Putting singles and lists into a list in clojure - 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).

Related

Juxtaposed transducers

Let's imagine we want to compute two different functions on some given input. How can we do that with transducers?
For example, let's say we have these two transducers:
(def xf-dupl (map #(* 2 %)))
(def xf-inc (map inc))
Now, I would like some function f that takes a collection of transducers and returns a new transducer that combines them, as follows:
(into [] (f [xf-dupl xf-inc]) (range 5))
; => [[0 2 4 6 8] [1 2 3 4 5]]
There should probably be a very simple solution to this, but I cannot find it.
Note: I have tried with cgrand/xforms library's transjuxt, but there I get the following
(into [] (x/transjuxt {:a xf-dupl :b xf-inc}) (range 5))
; => [{:a 0 :b 1}]
Thanks for your help!
Using cgrand/xforms you can define f as
(defn f
[xfs]
(comp
(x/multiplex (zipmap (range) xfs))
(x/by-key (x/into []))
(map second)))
Calling f as you outlined in your question yields
user> (into [] (f [xf-dupl xf-inc]) (range 5))
[[0 2 4 6 8] [1 2 3 4 5]]

Return a sequence with the elements not in common to two original sequences by using clojure

I have two sequences, which can be vector or list. Now I want to return a sequence whose elements are not in common to the two sequences.
Here is an example:
(removedupl [1 2 3 4] [2 4 5 6]) = [1 3 5 6]
(removeddpl [] [1 2 3 4]) = [1 2 3 4]
I am pretty puzzled now. This is my code:
(defn remove-dupl [seq1 seq2]
(loop [a seq1 b seq2]
(if (not= (first a) (first b))
(recur a (rest b)))))
But I don't know what to do next.
I encourage you to think about this problem in terms of set operations
(defn extrasection [& ss]
(clojure.set/difference
(apply clojure.set/union ss)
(apply clojure.set/intersection ss)))
Such a formulation assumes that the inputs are sets.
(extrasection #{1 2 3 4} #{2 4 5 6})
=> #{1 6 3 5}
Which is easily achieved by calling the (set ...) function on lists, sequences, or vectors.
Even if you prefer to stick with a sequence oriented solution, keep in mind that searching both sequences is an O(n*n) task if you scan both sequences [unless they are sorted]. Sets can be constructed in one pass, and lookup is very fast. Checking for duplicates is an O(nlogn) task using a set.
I'm still new to Clojure but I think the functional mindset is more into composing functions than actually doing it "by hand", so I propose the following solution:
(defn remove-dupl [seq1 seq2]
(concat
(remove #(some #{%} seq1) seq2)
(remove #(some #{%} seq2) seq1)))
EDIT: I think it is better if we define that remove part as a local function and reuse it:
(defn remove-dupl [seq1 seq2]
(let [removing (fn [x y] (remove #(some #{%} x) y))]
(concat (removing seq1 seq2) (removing seq2 seq1))))
EDIT2: As commented by TimothyPratley
(defn remove-dupl [seq1 seq2]
(let [removing (fn [x y] (remove (set x) y))]
(concat (removing seq1 seq2) (removing seq2 seq1))))
There are several problems with your code.
It doesn't test for the end of either sequence argument.
It steps through b but not a.
It implicitly returns nil when any two sequences have the same
first element.
You want to remove the common elements from the concatenated sequences. You have to work out the common elements first, otherwise you don't know what to remove. So ...
We use
clojure.set/intersection to find the common elements,
concat to stitch the collections together.
remove to remove (1) from (2).
vec to convert to a vector.
Thus
(defn removedupl [coll1 coll2]
(let [common (clojure.set/intersection (set coll1) (set coll2))]
(vec (remove common (concat coll1 coll2)))))
... which gives
(removedupl [1 2 3 4] [2 4 5 6]) ; [1 3 5 6]
(removedupl [] [1 2 3 4]) ; [1 2 3 4]
... as required.

clojure: pop and push

I'm looking for a sequential data structure which is perfect for the following operation. The lenght of the list remains constant, it will never be longer or shorter than a fixed length.
Omit the first item and add x to the end.
(0 1 2 3 4 5 6 7 8 9)
(pop-and-push "10")
(1 2 3 4 5 6 7 8 9 10)
There is only one other reading-operation that has to be done equally often:
(last coll)
pop-and-push could be implemented like this:
(defn pop-and-push [coll x]
(concat (pop coll) ["x"]))
(unfortunately this does not work with sequences produced by e.g. range, it just pops when the sequence declared by the literals '(..) is passed.)
but is this optimal?
The main issue here (once we change "x" to x) is that concat returns a lazy-seq, and lazy-seqs are invalid args to pop.
user=> (defn pop-and-push [coll x] (concat (pop coll) [x]))
#'user/pop-and-push
user=> (pop-and-push [1 2 3] 4)
(1 2 4)
user=> (pop-and-push *1 5)
ClassCastException clojure.lang.LazySeq cannot be cast to clojure.lang.IPersistentStack clojure.lang.RT.pop (RT.java:730)
My naive preference would be to use a vector. This function is easy to implement with subvec.
user=> (defn pop-and-push [v x] (conj (subvec (vec v) 1) x))
#'user/pop-and-push
user=> (pop-and-push [1 2 3] 4)
[2 3 4]
user=> (pop-and-push *1 5)
[3 4 5]
as you can see, this version can actually operate on its own return value
As suggested in the comments, PersistentQueue is made for this situation:
user=> (defn pop-and-push [v x] (conj (pop v) x))
#'user/pop-and-push
user=> (pop-and-push (into clojure.lang.PersistentQueue/EMPTY [1 2 3]) 4)
#object[clojure.lang.PersistentQueue 0x50313382 "clojure.lang.PersistentQueue#7c42"]
user=> (into [] *1)
[2 3 4]
user=> (pop-and-push *2 5)
#object[clojure.lang.PersistentQueue 0x4bd31064 "clojure.lang.PersistentQueue#8023"]
user=> (into [] *1)
[3 4 5]
The PersistentQueue data structure, though less convenient to use in some ways, is actually optimized for this usage.

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)

Map with an accumulator in Clojure?

I want to map over a sequence in order but want to carry an accumulator value forward, like in a reduce.
Example use case: Take a vector and return a running total, each value multiplied by two.
(defn map-with-accumulator
"Map over input but with an accumulator. func accepts [value accumulator] and returns [new-value new-accumulator]."
[func accumulator collection]
(if (empty? collection)
nil
(let [[this-value new-accumulator] (func (first collection) accumulator)]
(cons this-value (map-with-accumulator func new-accumulator (rest collection))))))
(defn double-running-sum
[value accumulator]
[(* 2 (+ value accumulator)) (+ value accumulator)])
Which gives
(prn (pr-str (map-with-accumulator double-running-sum 0 [1 2 3 4 5])))
>>> (2 6 12 20 30)
Another example to illustrate the generality, print running sum as stars and the original number. A slightly convoluted example, but demonstrates that I need to keep the running accumulator in the map function:
(defn stars [n] (apply str (take n (repeat \*))))
(defn stars-sum [value accumulator]
[[(stars (+ value accumulator)) value] (+ value accumulator)])
(prn (pr-str (map-with-accumulator stars-sum 0 [1 2 3 4 5])))
>>> (["*" 1] ["***" 2] ["******" 3] ["**********" 4] ["***************" 5])
This works fine, but I would expect this to be a common pattern, and for some kind of map-with-accumulator to exist in core. Does it?
You should look into reductions. For this specific case:
(reductions #(+ % (* 2 %2)) 2 (range 2 6))
produces
(2 6 12 20 30)
The general solution
The common pattern of a mapping that can depend on both an item and the accumulating sum of a sequence is captured by the function
(defn map-sigma [f s] (map f s (sigma s)))
where
(def sigma (partial reductions +))
... returns the sequence of accumulating sums of a sequence:
(sigma (repeat 12 1))
; (1 2 3 4 5 6 7 8 9 10 11 12)
(sigma [1 2 3 4 5])
; (1 3 6 10 15)
In the definition of map-sigma, f is a function of two arguments, the item followed by the accumulator.
The examples
In these terms, the first example can be expressed
(map-sigma (fn [_ x] (* 2 x)) [1 2 3 4 5])
; (2 6 12 20 30)
In this case, the mapping function ignores the item and depends only on the accumulator.
The second can be expressed
(map-sigma #(vector (stars %2) %1) [1 2 3 4 5])
; (["*" 1] ["***" 2] ["******" 3] ["**********" 4] ["***************" 5])
... where the mapping function depends on both the item and the accumulator.
There is no standard function like map-sigma.
General conclusions
Just because a pattern of computation is common does not imply that
it merits or requires its own standard function.
Lazy sequences and the sequence library are powerful enough to tease
apart many problems into clear function compositions.
Rewritten to be specific to the question posed.
Edited to accommodate the changed second example.
Reductions is the way to go as Diego mentioned however to your specific problem the following works
(map #(* % (inc %)) [1 2 3 4 5])
As mentioned you could use reductions:
(defn map-with-accumulator [f init-value collection]
(map first (reductions (fn [[_ accumulator] next-elem]
(f next-elem accumulator))
(f (first collection) init-value)
(rest collection))))
=> (map-with-accumulator double-running-sum 0 [1 2 3 4 5])
(2 6 12 20 30)
=> (map-with-accumulator stars-sum 0 [1 2 3 4 5])
("*" "***" "******" "**********" "***************")
It's only in case you want to keep the original requirements. Otherwise I'd prefer to decompose f into two separate functions and use Thumbnail's approach.