Iterate a map in Clojure - clojure

I have some data as seen bellow.
(def my-data
{1 {:x 63 :y 14 :z [30 26]}
2 {:x 22 :y 15 :z [32 66]}
3 {:x 24 :y 16 :z [38 40]}})
I want to iterate through my-data to get the result bellow:
1 2 3
This is what I have done so far
(println (-> (seq my-data)(ffirst ,,,)
and my result
1

If you want to print each key in a different line, you can use either of these:
(doseq [item (keys my-data)]
(println item))
(run! println (keys my-data))

You just go:
(println (keys my-data))

The non-popular answer: this will not work for bigger maps. Small maps are ordered (insert order), but larger maps switch types and are no longer ordered/sorted. So "first" no longer makes sense.
user=> (type (zipmap (range 8) (range 8)))
; => #<Class#34f7234e clojure.lang.PersistentArrayMap>
user=> (take 8 (keys (zipmap (range 8) (range 8))))
; => (0 1 2 3 4 5 6 7)
user=> (type (zipmap (range 9) (range 9)))
; => #<Class#45dd4eda clojure.lang.PersistentHashMap>
user=> (take 8 (keys (zipmap (range 9) (range 9))))
; => (0 7 1 4 6 3 2 5)
The other answers are correct for larger maps, if you you it via sorted-map or sorted-map-by, if sorting your keys solves the problem. If you need the order you might be better off using vectors of vectors.

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]]

How to find odd item in given list of numbers?(PS here odd means different)

I have to display the index of the odd items in a given list of numbers.
I tried getting the remainder but I have to divide the given list by [2 3 5 10] in order to know which element is odd.
(defn odd_one_out [y]
(println (map #(rem % 2) y)))
(odd_one_out [2 8 9 200 56])
I expect the output 9 or index of 9 since it is the only element which cannot be divided by 2.
The output i am getting is 0 0 1 0 0
If I understand correctly, you want to find the number which is uniquely indivisible for given divisors. You could use group-by to group the numbers by their divisibility, then find the one(s) that are indivisible by exactly one divisor.
(defn odd-one-out [nums divs]
(->> nums
(group-by #(map (fn [d] (zero? (mod % d))) divs))
(some (fn [[div-flags nums']]
(and (= 1 (count nums'))
(= 1 (count (filter true? div-flags)))
(first nums'))))))
(odd-one-out [2 8 9 200 56] [2 3 5 10]) ;; => 9
(odd-one-out [2 10 20 60 90] [2 3 5 10]) ;; => 2
If you just want to extend your current function, you could use map-indexed,which will give you this list ([0 0] [1 0] [2 1] [3 0] [4 0]), which you can then filter to keep only the vectors that have 1 in the second position. This will return the index of the odd character.
(defn odd-one-out [y]
(->> y
(map #(rem % 2))
(map-indexed vector)
(filter #(= 1 (second %)))
(map first)))
(odd-one-out [2 8 9 200 56])
(2)
Even better would be to use the function odd? from Clojure's standard library.
(->> [2 8 9 200 56]
(map odd?)
(map-indexed vector)
(filter #(second %))
(map first))
Another version using keep.
(to return the index)
(->> [2 8 9 200 56]
(map-indexed vector)
(keep #(when (odd? (second %))
(first %))))
(2)
(to return the value)
(->> [2 8 9 200 56]
(map-indexed vector)
(keep #(when (odd? (second %))
(second %))))
(9)

Single duplicate in a vector

Given a list of integers from 1 do 10 with size of 5, how do I check if there are only 2 same integers in the list?
For example
(check '(2 2 4 5 7))
yields yes, while
(check '(2 1 4 4 4))
or
(check '(1 2 3 4 5))
yields no
Here is a solution using frequencies to count occurrences and filter to count the number of values that occur only twice:
(defn only-one-pair? [coll]
(->> coll
frequencies ; map with counts of each value in coll
(filter #(= (second %) 2)) ; Keep values that have 2 occurrences
count ; number of unique values with only 2 occurrences
(= 1))) ; true if only one unique val in coll with 2 occurrences
Which gives:
user=> (only-one-pair? '(2 1 4 4 4))
false
user=> (only-one-pair? '(2 2 4 5 7))
true
user=> (only-one-pair? '(1 2 3 4 5))
false
Intermediate steps in the function to get a sense of how it works:
user=> (->> '(2 2 4 5 7) frequencies)
{2 2, 4 1, 5 1, 7 1}
user=> (->> '(2 2 4 5 7) frequencies (filter #(= (second %) 2)))
([2 2])
user=> (->> '(2 2 4 5 7) frequencies (filter #(= (second %) 2)) count)
1
Per a suggestion, the function could use a more descriptive name and it's also best practice to give predicate functions a ? at the end of it in Clojure. So maybe something like only-one-pair? is better than just check.
Christian Gonzalez's answer is elegant, and great if you are sure you are operating on a small input. However, it is eager: it forces the entire input list even when itcould in principle tell sooner that the result will be false. This is a problem if the list is very large, or if it is a lazy list whose elements are expensive to compute - try it on (list* 1 1 1 (range 1e9))! I therefore present below an alternative that short-circuits as soon as it finds a second duplicate:
(defn exactly-one-duplicate? [coll]
(loop [seen #{}
xs (seq coll)
seen-dupe false]
(if-not xs
seen-dupe
(let [x (first xs)]
(if (contains? seen x)
(and (not seen-dupe)
(recur seen (next xs) true))
(recur (conj seen x) (next xs) seen-dupe))))))
Naturally it is rather more cumbersome than the carefree approach, but I couldn't see a way to get this short-circuiting behavior without doing everything by hand. I would love to see an improvement that achieves the same result by combining higher-level functions.
(letfn [(check [xs] (->> xs distinct count (= (dec (count xs)))))]
(clojure.test/are [input output]
(= (check input) output)
[1 2 3 4 5] false
[1 2 1 4 5] true
[1 2 1 2 1] false))
but I like a shorter (but limited to exactly 5 item lists):
(check [xs] (->> xs distinct count (= 4)))
In answer to Alan Malloy's plea, here is a somewhat combinatory solution:
(defn check [coll]
(let [accums (reductions conj #{} coll)]
(->> (map contains? accums coll)
(filter identity)
(= (list true)))))
This
creates a lazy sequence of the accumulating set;
tests it against each corresponding new element;
filters for the true cases - those where the element is already present;
tests whether there is exactly one of them.
It is lazy, but does duplicate the business of scanning the given collection. I tried it on Alan Malloy's example:
=> (check (list* 1 1 1 (range 1e9)))
false
This returns instantly. Extending the range makes no difference:
=> (check (list* 1 1 1 (range 1e20)))
false
... also returns instantly.
Edited to accept Alan Malloy's suggested simplification, which I have had to modify to avoid what appears to be a bug in Clojure 1.10.0.
you can do something like this
(defn check [my-list]
(not (empty? (filter (fn[[k v]] (= v 2)) (frequencies my-list)))))
(check '(2 4 5 7))
(check '(2 2 4 5 7))
Similar to others using frequencies - just apply twice
(-> coll
frequencies
vals
frequencies
(get 2)
(= 1))
Positive case:
(def coll '(2 2 4 5 7))
frequencies=> {2 2, 4 1, 5 1, 7 1}
vals=> (2 1 1 1)
frequencies=> {2 1, 1 3}
(get (frequencies #) 2)=> 1
Negative case:
(def coll '(2 1 4 4 4))
frequencies=> {2 1, 1 1, 4 3}
vals=> (1 1 3)
frequencies=> {1 2, 3 1}
(get (frequencies #) 2)=> nil

Clojure: how to move vector elements in a map elegantly

In clojure, I am trying to accomplish the following logic:
Input:
{:a [11 22 33] :b [10 20 30]}, 2
Output:
{:a [11] :b [10 20 30 22 33]}
i.e. Move the last 2 elements from :a to :b
Is there a clojurish way for this operation?
Since you're effectively modifying both mappings in the map, it's probably easiest to explicitly deconstruct the map and just return the new map via a literal, using subvec and into for the vector manipulation:
(defn move [m n]
(let [{:keys [a b]} m
i (- (count a) n)
left (subvec a 0 i)
right (subvec a i)]
{:a left :b (into b right)}))
(move {:a [11 22 33] :b [10 20 30]} 2)
;;=> {:a [11], :b [10 20 30 22 33]}
As a bonus, this particular implementation is both very idiomatic and very fast.
Alternatively, using the split-at' function from here, you could write it like this:
(defn split-at' [n v]
[(subvec v 0 n) (subvec v n)])
(defn move [m n]
(let [{:keys [a b]} m
[left right] (split-at' (- (count a) n) a)]
{:a left :b (into b right)}))
First, using the sub-vec in the other answers will throw an IndexOutOfBoundsException when the number of elements to be moved is greater than the size of the collection.
Secondly, the destructuring, the way most have done here, couples the function to one specific data structure. This being, a map with keys :a and :b and values for these keys that are vectors. Now if you change one of the keys in the input, then you need to also change it in move function.
My solution follows:
(defn move [colla collb n]
(let [newb (into (into [] collb) (take-last n colla))
newa (into [] (drop-last n colla))]
[newa newb]))
This should work for any collection and will return vector of 2 vectors. My solution is far more reusable. Try:
(move (range 100000) (range 200000) 10000)
Edit:
Now you can use first and second to access the vector you need in the return.
I would do it just a little differently than Josh:
(defn tx-vals [ {:keys [a b]} num-to-move ]
{:a (drop-last num-to-move a)
:b (concat b (take-last num-to-move a)) } )
(tx-vals {:a [11 22 33], :b [10 20 30]} 2)
=> {:a (11), :b (10 20 30 22 33)}
Update
Sometimes it may be more convenient to use the clojure.core/split-at function as follows:
(defn tx-vals-2 [ {:keys [a b]} num-to-move ]
(let [ num-to-keep (- (count a) num-to-move)
[a-head, a-tail] (split-at num-to-keep a) ]
{ :a a-head
:b (concat b a-tail) } ))
If vectors are preferred on output (my favorite!), just do:
(defn tx-vals-3 [ {:keys [a b]} num-to-move ]
(let [ num-to-keep (- (count a) num-to-move)
[a-head, a-tail] (split-at num-to-keep a) ]
{:a (vec a-head)
:b (vec (concat b a-tail))} ))
to get the results:
(tx-vals-2 data 2) => {:a (11), :b (10 20 30 22 33)}
(tx-vals-3 data 2) => {:a [11], :b [10 20 30 22 33]}
(defn f [{:keys [a b]} n]
(let [last-n (take-last n a)]
{:a (into [] (take (- (count a) n) a))
:b (into b last-n)}))
(f {:a [11 22 33] :b [10 20 30]} 2)
=> {:a [11], :b [10 20 30 22 33]}
In case if the order of those items does not matter, here is my attempt:
(def m {:a [11 22 33] :b [10 20 30]})
(defn so-42476918 [{:keys [a b]} n]
(zipmap [:a :b] (map vec (split-at (- (count a) n) (concat a b)))))
(so-42476918 m 2)
gives:
{:a [11], :b [22 33 10 20 30]}
i would go with an approach, which differs a bit from the previous answers (well, technically it is the same, but it differs on the application-scale level).
First of all, transferring data between two collections is quite a frequent task, so it at least deserves some special utility function for that in your library:
(defn transfer [from to n & {:keys [get-from put-to]
:or {:get-from :start :put-to :end}}]
(let [f (if (= get-from :end)
(partial split-at (- (count from) n))
(comp reverse (partial split-at n)))
[from swap] (f from)]
[from (if (= put-to :start)
(concat swap to)
(concat to swap))]))
ok, it looks verbose, but it lets you transfer data from start/end of one collection to start/end of the other:
user> (transfer [1 2 3] [4 5 6] 2)
[(3) (4 5 6 1 2)]
user> (transfer [1 2 3] [4 5 6] 2 :get-from :end)
[(1) (4 5 6 2 3)]
user> (transfer [1 2 3] [4 5 6] 2 :put-to :start)
[(3) (1 2 4 5 6)]
user> (transfer [1 2 3] [4 5 6] 2 :get-from :end :put-to :start)
[(1) (2 3 4 5 6)]
So what's left, is to make your domain specific function on top of it:
(defn move [data n]
(let [[from to] (transfer (:a data) (:b data) n
:get-from :end
:put-to :end)]
(assoc data
:a (vec from)
:b (vec to))))
user> (move {:a [1 2 3 4 5] :b [10 20 30 40] :c [:x :y]} 3)
{:a [1 2], :b [10 20 30 40 3 4 5], :c [:x :y]}

How to find numbers that occur more than once in a list using clojure

I have a list of numbers 2 4 3 7 4 9 8 5 12 24 8.
I need to find numbers which are repeated more than once in clojure.
I have used frequencies function to find. But the result is
{2 1,4 2,3 1,7 1,9 1,8 2,5 1,12 1,24 1}
I intially thought of considering them as key value and then take each key value once and see if val is > 1. if value is greater than 1 then I need to inc 1.
But I am unable to work this out.
Can anyone please help me??
Is there anyway I can make this into [[2 1][4 2][3 1][7 1][9 1][8 2][5 1][12 1][24 1]] and consider each vector recursively or any better idea you can think of.
Thank you.
The function below will just continue on where you have stuck:
(defn find-duplicates [numbers]
(->> numbers
(frequencies)
(filter (fn [[k v]] (> v 1)))
(keys)))
It will filter map entries that have values greater than 1 and then extract their keys.
(find-duplicates [2 4 3 7 4 9 8 5 12 24 8])
;; => (4 8)
If you want the repeated items:
(defn repeated [coll]
(->> coll
frequencies
(remove #(= 1 (val %)))
keys))
(repeated [2 4 3 7 4 9 8 5 12 24 8])
;(4 8)
If you just want to count them:
(defn repeat-count [coll]
(->> coll
frequencies
(remove #(= 1 (val %)))
count))
(repeat-count [2 4 3 7 4 9 8 5 12 24 8])
;2
You can do it lazily, so that it will work on an endless sequence:
(defn repeated [coll]
((fn ff [seen xs]
(lazy-seq
(when-let [[y & ys] (seq xs)]
(case (seen y)
::several (ff seen ys)
::once (cons y (ff (assoc seen y ::several) ys))
(ff (assoc seen y ::once) ys)))))
{} coll))
(repeated [2 4 3 7 4 9 8 5 12 24 8])
;(4 8)
This is similar to core distinct.
... and finally, for brevity, ...
(defn repeated [coll]
(for [[k v] (frequencies coll) :when (not= v 1)] k))
I stole the use of keys from Piotrek Byzdyl's answer. It is only supposed to apply to a map. but works perfectly well here on a sequence of map-entries.
(->> s (group-by identity) (filter (comp next val)) keys)
You are on the right track.
If you seq over hash-map, e. g. via map, you get the kv tuple structure you described and can destructure an individual tuple in the element transformation function:
(->> s
(frequencies)
(map (fn [[number times]]
(cond-> number ; take number
(> times 1) (inc))))) ; inc if (times > 1), otherwise return number
You can use this approach.
(def c [2 4 3 7 4 9 8 5 12 24 8])
(->> c
sort
(partition-by identity)
(filter #(> (count %) 1))
(map first))