How do I build up an array using let in Clojure? - clojure

(test [1 2 3]) is returning [], not [1 2 3], why?
(defn test [some-array]
(let [x []]
(doseq [i some-array]
(conj x i))
x))
(test [1 2 3])
EDIT: a comment below suggested I am trying an imperative approach with a functional language, and that's probably correct. What I am trying to do is build up a vector of vectors using an initial sequence of values (inside a vector in this case) as starting data. I guess I could try to transform each value in the vector and return it, but that seems harder conceptually (from an imperative mindset) than taking a starting vector and using it to build out a new one and return that.
As an example, suppose I had a function that takes 1 and returns "one", and I wanted to have a function take [1 2 3] and return [[1 "one"][2 "two"][3 "three"]].

Clojure's focus is on immutable data and functional programming. Your
code there feels like you want to do some imperative style ideas here.
Your test there could as well be identity - a copy of some immutable
data structure, is just the immutable data structure itself.
If your example there is oversimplified and you want to "append" to some
x with data inside it, you could use into.
edit
To transform a sequence one-by-one (e.g. each input results in
a different output), use map (or mapv to get a vector and make it
eager). E.g.
(def numbers
{1 "one"
2 "two"
3 "three"})
(defn test [some-array]
(mapv #(vector % (numbers %)) some-array))
(println (test [1 2 3]))
; → [[1 one] [2 two] [3 three]]
(Bonus points for using juxt as mapping function)

As others have pointed out, some ways of building the result are easier than others. In this case, we see that each element of the result vector is computed from a corresponding element in the input vector. This is a good indication to use map (or mapv):
(def nums ["zero" "one" "two" "three" "four" "five"])
(defn arr-test [xs]
(mapv (juxt identity nums) xs))

there is also a handy util clojure.pprint/cl-format in core library to get string representation of numbers (and much more!):
user> (def num-str (partial clojure.pprint/cl-format nil "~R"))
#'user/num-str
user> (mapv (juxt identity num-str) [0 1 2 234 2455323 1541524152352356235625])
;;=> [[0 "zero"]
;; [1 "one"]
;; [2 "two"]
;; [234 "two hundred thirty-four"]
;; [2455323
;; "two million, four hundred fifty-five thousand, three hundred twenty-three"]
;; [1541524152352356235625N
;; "one sextillion, five hundred forty-one quintillion, five hundred twenty-four quadrillion, one hundred fifty-two trillion, three hundred fifty-two billion, three hundred fifty-six million, two hundred thirty-five thousand, six hundred twenty-five"]]

You really don't want to do it that way - but if you did :-) you'd want to use loop instead of let:
(defn arr-test [some-array]
(let [digit-words {1 "one", 2 "two", 3 "three", 4 "four", 5 "five",
6 "six", 7 "seven", 8 "eight", 9 "nine", 0 "zero" }]
(loop [x []
a some-array]
(if (empty? a)
x
(recur (conj x [(first a) (digit-words (first a))]) (rest a))))))
A better way would be:
(defn arr-test [some-array]
(let [digit-words {1 "one", 2 "two", 3 "three", 4 "four", 5 "five",
6 "six", 7 "seven", 8 "eight", 9 "nine", 0 "zero" }]
(mapv #(vector % (digit-words %)) some-array)))

Related

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.

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)

How to convert map to a sequence?

Answers to this question explain how to convert maps, sequences, etc. to various sequences and collections, but do not say how to convert a map to a sequence of alternating keys and values. Here is one way:
(apply concat {:a 1 :b 2})
=> (:b 2 :a 1)
Some alternatives that one might naively think would produce the same result, don't, including passing the map to vec, vector, seq, sequence, into [], into (), and flatten. (Sometimes it's easier to try it than to think it through.)
Is there anything simpler than apply concat?
You can also do
(mapcat identity {:a 1 :b 2})
or
(mapcat seq {:a 1 :b 2})
As #noisesmith gently hints below, the following answer is seductive but wrong: left as a warning to other unwary souls! Counterexample:
((comp flatten seq) {[1 2] [3 4], 5 [6 7]})
; (1 2 3 4 5 6 7)
(comp flatten seq) does the job:
((comp flatten seq) {1 2, 3 4})
; (1 2 3 4)
But flatten on its own doesn't:
(flatten {1 2, 3 4})
; ()
I'm surprised it doesn't work, and in that case it should return nil, not ().
None of the others you mention: vec, vector ... , does anything to the individual [key value] pairs that the map presents itself as a sequence of.

Split a vector into vector of vectors in clojure instead of vector of lists

The clojure documentation of split-at states that it takes a collection of elements and returns a vector of two lists, each containing elements greater or smaller than a given index:
(split-at 2 [1 2 3 4 5])
[(1 2) (3 4 5)]
What I want is this:
(split-at' 2 [1 2 3 4 5])
[[1 2] [3 4 5]]
This is a collection cut into two collections that keep the order of the elements (like vectors), preferably without performance penalties.
What is the usual way to do this and are there any performance optimized ways to do it?
If you're working exclusively with vectors, one option would be to use subvec.
(defn split-at' [idx v]
[(subvec v 0 idx) (subvec v idx)])
(split-at' 2 [1 2 3 4 5])
;; => [[1 2] [3 4 5]]
As regards to performance, the docs on subvec state:
This operation is O(1) and very fast, as
the resulting vector shares structure with the original and no
trimming is done.
Why not extend the core function with "vec" function ?
So based on split-at definition:
(defn split-at
"Returns a vector of [(take n coll) (drop n coll)]"
{:added "1.0"
:static true}
[n coll]
[(take n coll) (drop n coll)])
We can add vec to each element of the vector result
(defn split-at-vec
[n coll]
[(vec (take n coll)) (vec (drop n coll))])
Releated to "performance penalties" i think that when you transform your lazy seqs in favor of vector then you loose the lazy performance.

Clojure: How to replace an element in a nested list?

I have this deeply nested list (list of lists) and I want to replace a single arbitrary element in the list. How can I do this ? (The built-in replace might replace many occurrences while I need to replace only one element.)
As everyone else already said, using lists is really not a good idea if you need to do this kind of thing. Random access is what vectors are made for. assoc-in does this efficiently. With lists you can't get away from recursing down into the sublists and replacing most of them with altered versions of themselves all the way back up to the top.
This code will do it though, albeit inefficiently and clumsily. Borrowing from dermatthias:
(defn replace-in-list [coll n x]
(concat (take n coll) (list x) (nthnext coll (inc n))))
(defn replace-in-sublist [coll ns x]
(if (seq ns)
(let [sublist (nth coll (first ns))]
(replace-in-list coll
(first ns)
(replace-in-sublist sublist (rest ns) x)))
x))
Usage:
user> (def x '(0 1 2 (0 1 (0 1 2) 3 4 (0 1 2))))
#'user/x
user> (replace-in-sublist x [3 2 0] :foo)
(0 1 2 (0 1 (:foo 1 2) 3 4 (0 1 2)))
user> (replace-in-sublist x [3 2] :foo)
(0 1 2 (0 1 :foo 3 4 (0 1 2)))
user> (replace-in-sublist x [3 5 1] '(:foo :bar))
(0 1 2 (0 1 (0 1 2) 3 4 (0 (:foo :bar) 2)))
You'll get IndexOutOfBoundsException if you give any n greater than the length of a sublist. It's also not tail-recursive. It's also not idiomatic because good Clojure code shies away from using lists for everything. It's horrible. I'd probably use mutable Java arrays before I used this. I think you get the idea.
Edit
Reasons why lists are worse than vectors in this case:
user> (time
(let [x '(0 1 2 (0 1 (0 1 2) 3 4 (0 1 2)))] ;'
(dotimes [_ 1e6] (replace-in-sublist x [3 2 0] :foo))))
"Elapsed time: 5201.110134 msecs"
nil
user> (time
(let [x [0 1 2 [0 1 [0 1 2] 3 4 [0 1 2]]]]
(dotimes [_ 1e6] (assoc-in x [3 2 0] :foo))))
"Elapsed time: 2925.318122 msecs"
nil
You also don't have to write assoc-in yourself, it already exists. Look at the implementation for assoc-in sometime; it's simple and straightforward (compared to the list version) thanks to vectors giving efficient and easy random access by index, via get.
You also don't have to quote vectors like you have to quote lists. Lists in Clojure strongly imply "I'm calling a function or macro here".
Vectors (and maps, sets etc.) can be traversed via seqs. You can transparently use vectors in list-like ways, so why not use vectors and have the best of both worlds?
Vectors also stand out visually. Clojure code is less of a huge blob of parens than other Lisps thanks to widespread use of [] and {}. Some people find this annoying, I find it makes things easier to read. (My editor syntax-highlights (), [] and {} differently which helps even more.)
Some instances I'd use a list for data:
If I have an ordered data structure that needs to grow from the front, that I'm never going to need random-access to
Building a seq "by hand", as via lazy-seq
Writing a macro, which needs to return code as data
For the simple cases a recursive substitution function will give you just what you need with out much extra complexity. when things get a little more complex its time to crack open clojure build in zipper functions: "Clojure includes purely functional, generic tree walking and editing, using a technique called a zipper (in namespace zip)."
adapted from the example in: http://clojure.org/other_libraries
(defn randomly-replace [replace-with in-tree]
(loop [loc dz]
(if (zip/end? loc)
(zip/root loc)
(recur
(zip/next
(if (= 0 (get-random-int 10))
(zip/replace loc replace-with)
loc)))))
these will work with nested anything (seq'able) even xmls
It sort of doesn't answer your question, but if you have vectors instead of lists:
user=> (update-in [1 [2 3] 4 5] [1 1] inc)
[1 [2 4] 4 5]
user=> (assoc-in [1 [2 3] 4 5] [1 1] 6)
[1 [2 6] 4 5]
So if possible avoid lists in favour of vectors for the better access behaviour. If you have to work with lazy-seq from various sources, this is of course not much of an advice...
You could use this function and adapt it for your needs (nested lists):
(defn replace-item
"Returns a list with the n-th item of l replaced by v."
[l n v]
(concat (take n l) (list v) (drop (inc n) l)))
A simple-minded suggestion from the peanut gallery:
copy the inner list to a vector;
fiddle that vector's elements randomly and to your heart's content using assoc;
copy the vector back to a list;
replace the nested list in the outer list.
This might waste some performance; but if this was a performance sensitive operation you'd be working with vectors in the first place.