clojure: how to get several items by index out of vector - clojure

I am using the following code to extract data by index of [1 2], is there any shorter solution?
(vec (map #(nth ["a" "b" "c"] % ) [1 2]))

mapv maps into a vector, and vectors when applied as functions do index lookup
(mapv ["a" "b" "c"] [1 2])

If you want ONLY the first and second index of a vector, there are many ways...
A simple sub vector can be used to persist the first index until the third index.
(subvec ["a" "b" "c"] 1 3)
You can map the vector and apply your vector to the first and second index to return the last two indices as a vector.
(mapv ["a" "b" "c"] [1 2])
Using the thread-last macro, you can take 3 indices and drop the first.
(->> ["a" "b" "c"] (take 3) (drop 1))
If you have a vector defined with n indices, and all you need is the last n indices, drop base 0 to return the last n.
(drop 1 ["a" "b" "c"])

Related

Clojure highest 3 values of a map

Hi l'm trying to do a function that returns the 3 most commom strings
(take 3 (sort-by val > (frequencies s))))
(freq ["hi" "hi" "hi" "ola" "hello" "hello" "string" "str" "ola" "hello" "hello" "str"])
l've got this so far but a noticed that if there are more than 1 string with the same frenquency it won't return. Is there a way to filter the values of the frequencies funcition by their highest (eventually the top 3 highest)?
Thanks in advance.
I would propose slightly different solution which involves inverting frequencies map with group-by value (which is the items' count):
(->> data
frequencies
(group-by val))
;;{3 [["hi" 3]],
;; 2 [["ola" 2] ["str" 2]],
;; 4 [["hello" 4]],
;; 1 [["string" 1]]}
so the only thing you need is to just sort and process it:
(->> data
frequencies
(group-by val)
(sort-by key >)
(take 3)
(mapv (fn [[k vs]] {:count k :items (mapv first vs)})))
;;[{:count 4, :items ["hello"]}
;; {:count 3, :items ["hi"]}
;; {:count 2, :items ["ola" "str"]}]
frequencies gives you a map, where the keys are the original values to
investigate and the values in that map are the frequency of those
values. For your result you are interested for all original values,
that have the most occurrences including those original values with the
same occurrences.
One way would be to "invert" the frequencies result, to get a map from
occurrences to all original values with that occurrence. Then you can
get the highest N keys and from this map and select them (by using
a "sorted map" for inverting the map, we get the sorting by keys without
further steps).
(defn invert-map
([source]
(invert-map source {}))
([source target]
(reduce (fn [m [k v]]
(update m v (fnil conj []) k))
target
source)))
(assert (=
{1 ["do" "re"]}
(invert-map {"do" 1 "re" 1})))
(defn freq
[n s]
(let [fs (invert-map (frequencies s) (sorted-map-by >))
top-keys (take n (keys fs))]
(select-keys fs top-keys)))
(assert (=
{4 ["hello"], 3 ["hi"], 2 ["ola" "str"]}
(freq 3 ["hi" "hi" "hi" "ola" "hello" "hello" "string" "str" "ola" "hello" "hello" "str"])))

What is the Clojure equivalent of Scala's zipWithIndex?

Scala Seq has the zipWithIndex method:
def zipWithIndex[A1 >: A, That](implicit bf: CanBuildFrom[Seq[A], (A1, Int), That]): That
Zips this sequence with its indices.
returns: A new sequence containing pairs consisting of all elements of this sequence paired with their index. Indices start at 0.
Example: List("a", "b", "c").zipWithIndex = List(("a", 0), ("b", 1), ("c", 2))
What is the equivalent function in Clojure?
Clojure's map-indexed will give you an indexed list of elements in a collection.
user=> (map-indexed vector "foo")
([0 \f] [1 \o] [2 \o])
As #jmargolisvt answered map-indexed is a good solution.
As your example got index inverted with collection items, you can always compose with reverse:
(map-indexed (comp reverse list) ["a", "b", "c"])
Or map over two sequences:
(map list ["a", "b", "c"] (range))

How to transpose a nested vector in clojure

I have the following variable
(def a [[1 2] [3 4] [5 6]])
and want to return
[[1 3 5][2 4 6]]
and if input is
[[1 2] [3 4] [5 6] [7 8 9]] then the required result is
[[1 3 5 7] [2 4 6 8] [9]]
How to do it in clojure?
(persistent!
(reduce
(fn [acc e]
(reduce-kv
(fn [acc2 i2 e2]
(assoc! acc2 i2 ((fnil conj []) (get acc2 i2) e2)))
acc
e))
(transient [])
[[1 2 3] [:a :b] [\a] [111] [200 300 400 500]]))
;;=> [[1 :a \a 111 200] [2 :b 300] [3 400] [500]]
An empty vector can be updated via the update-in fn at the 0th index, a non-empty vector can be, additionally, updated at the index immediately following the last value.
The reduction here is about passing the outer accumulator to the inner reducing function, updating it accordingly, and then returning it back to the outer reducing function, which in turn will pass again to the inner rf for processing the next element.
EDIT: Updated to fastest version.
I like ifett's implementation, though it seems weird to use reduce-kv to build a vector that could be easily build with map/mapv.
So, here is how I would've done it:
(defn transpose [v]
(mapv (fn [ind]
(mapv #(get % ind)
(filter #(contains? % ind) v)))
(->> (map count v)
(apply max)
range)))
(->> (range)
(map (fn [i]
(->> a
(filter #(contains? % i))
(map #(nth % i)))))
(take-while seq))
Notice that this algorithm creates a lazy seq of lazy seqs so you that you will only pay for the transformations you really consume. If you insist on creating vectors instead, wrap the forms in vec at the necessary places - or if you are using Clojurescript or don't mind a Clojure 1.7 alpha use transducers to create vectors eagerly without paying for laziness or immutability:
(into []
(comp
(map (fn [i]
(into [] (comp (filter #(contains? % i))
(map #(nth % i)))
a)))
(take-while seq))
(range))
I find this easy to understand:
(defn nth-column [matrix n]
(for [row matrix] (nth row n)))
(defn transpose [matrix]
(for [column (range (count (first matrix)))]
(nth-column matrix column)))
(transpose a)
=> ((1 3 5) (2 4 6))
nth-column is a list comprehension generating a sequence from the nth element of each sequence (of rows).
Then transpose-matrix is simply iterating over the columns creating a sequence element for each, consisting of (nth-column matrix column) i.e. the sequence of elements for that column.
(map
(partial filter identity) ;;remove nil in each sub-list
(take-while
#(some identity %) ;;stop on all nil sub-list
(for [i (range)]
(map #(get % i) a)))) ;; get returns nil on missing values
Use get to have nil on missing values, iterate (for) on an infinite range, stop on all nil sub-list, remove nil from sub-lists. Add vector constructor before first map and in it's function (first argument) if you really need vectors.
EDIT: please leave a comment if you think this is not useful. We can all learn from mistakes.

Get first x number of elements from a hashmap in clojure

How does one retrieve the first x key value pairs from a sorted clojure map of 2x key value pairs
Simply use take on a sorted-map:
(def a (sorted-map 3 :a 2 :b 1 :c))
(take 2 a) ;; ([1 :c] [2 :b])

How to create a map from a list of key-value pairs using values as a predicate in Clojure?

Just started learning Clojure, so I imagine my main issue is I don't know how to formulate the problem correctly to find an existing solution. I have a map:
{[0 1 "a"] 2, [0 1 "b"] 1, [1 1 "a"] 1}
and I'd like to "transform" it to:
{[0 1] "a", [1 1] "a"}
i.e. use the two first elements of the composite key as they new key and the third element as the value for the key-value pair that had the highest value in the original map.
I can easily create a new map structure:
=> (into {} (for [[[x y z] v] {[0 1 "a"] 2, [0 1 "b"] 1, [1 1 "a"] 1}] [[x y] {z v}]))
{[0 1] {"b" 1}, [1 1] {"a" 1}}
but into accepts no predicates so last one wins. I also experimented with :let and merge-with but can't seem to correctly refer to the map, eliminate the unwanted pairs or replace values of the map while processing.
You can do this by threading together a series of sequence transformations.
(->> data
(group-by #(->> % key (take 2)))
vals
(map (comp first first (partial sort-by (comp - val))))
(map (juxt #(subvec % 0 2) #(% 2)))
(into {}))
;{[0 1] "a", [1 1] "a"}
... where
(def data {[0 1 "a"] 2, [0 1 "b"] 1, [1 1 "a"] 1})
You build up the solution line by line. I recommend you follow in the footsteps of the construction, starting with ...
(->> data
(group-by #(->> % key (take 2)))
;{(0 1) [[[0 1 "a"] 2] [[0 1 "b"] 1]], (1 1) [[[1 1 "a"] 1]]}
Stacking up layers of (lazy) sequences can run fairly slowly, but the transducers available in Clojure 1.7 will allow you to write faster code in this idiom, as seen in this excellent answer.
Into tends to be most useful when you just need to take a seq of values and with no additional transformation construct a result from it using only conj. Anything else where you are performing construction tends to be better suited by preprocessing such as sorting, or by a reduction which allows you to perform accumulator introspection such as you want here.
First of all we have to be able to compare two strings..
(defn greater? [^String a ^String b]
(> (.compareTo a b) 0))
Now we can write a transformation that compares the current value in the accumulator to the "next" value and keeps the maximum. -> used somewhat gratuitusly to make the update function more readable.
(defn transform [input]
(-> (fn [acc [[x y z] _]] ;; take the acc, [k, v], destructure k discard v
(let [key [x y]] ;; construct key into accumulator
(if-let [v (acc key)] ;; if the key is set
(if (greater? z v) ;; and z (the new val) is greater
(assoc acc key z) ;; then update
acc) ;; else do nothing
(assoc acc key z)))) ;; else update
(reduce {} input))) ;; do that over all [k, v]s from empty acc
user> (def m {[0 1 "a"] 2, [0 1 "b"] 1, [1 1 "a"] 1})
#'user/m
user> (->> m
keys
sort
reverse
(mapcat (fn [x]
(vector (-> x butlast vec)
(last x))))
(apply sorted-map))
;=> {[0 1] "a", [1 1] "a"}