How can I find the index of the smallest member of this vector in Clojure? - clojure

I have used the following expression to retrieve the index of the smallest number in a vector. However, I would like to avoid the use of .indexOf (for efficiency reasons and maybe numeric precision, although I guess the numbers are implicitly converted to strings).
(.indexOf [1 2 3 4 0 5]
(reduce #(if (< %1 %2) %1 %2) [1 2 3 4 0 5] ))
Would it be possible to do it differently using reduce?

user=> (first (apply min-key second (map-indexed vector [1 2 4 0 5])))
3

I'd suggest using loop/recur if you want to do this efficiently, perhaps something like the following:
(defn min-index [v]
(let [length (count v)]
(loop [minimum (v 0)
min-index 0
i 1]
(if (< i length)
(let [value (v i)]
(if (< value minimum)
(recur value i (inc i))
(recur minimum min-index (inc i))))
min-index))))
The idea is to iterate across the whole vector, keeping track of the minimum and the index of the minimum value found so far at each point.

You can also use reduce:
(def v [1 2 3 4 0 5])
(second (reduce (fn [[curr-min min-idx curr-idx] val]
(if (< val curr-min)
[val curr-idx (inc curr-idx)]
[curr-min min-idx (inc curr-idx)])) [(first v) 0 0] v)) ;; => 4
The result of reduce is actually a three-element vector consisting of the minimum value, its index, and an index tracker (which is not important), respectively. And it traverses the collection once.
The initial value provided to reduce is basically the first element of the collection.
I know the question is old, but it is here for posterity's sake.

Following up on #Alex Taggart's answer, using thread-last macro:
user=> (->> [1 2 4 0 5]
(map-indexed vector) ; [[0 1] [1 2] [2 4] [3 0] [4 5]]
(apply min-key second) ; [3 0]
first)
3

Related

Comparing each neighboring pairs in clojure vector

I'm learning Clojure. I found some exercises which require finding indexes for values in an array which are, for example, lower than next value. In Java I'd write
for (int i = 1; ...)
if (a[i-1] < a[i]) {result.add(i-1)}
in Clojure I found keep-indexed useful:
(defn with-keep-indexed [v]
(keep-indexed #(if (> %2 (get v %1)) %1) (rest v)))
It seems to works ok, but
is there a better way to do so?
This approach should work well for "find all values" or "find first value" (wrapped in first). But what if I need "find last". Then I have to either (with-keep-indexed (reverse v)) or (last (with-keep-indexed v)). Is there better way?
Edit: Example: for [1 1 2 2 1 2]
(with-keep-indexed [1 1 2 2 1 2])
;;=> (1 4)
Use partition to transform the vector to a sequence of consecutive pairs. Then use keep-indexed to add an index and filter them:
(defn indices< [xs]
(keep-indexed (fn [i ys]
(when (apply < ys) i))
(partition 2 1 xs)))
(indices< [1 1 2 2 1 2]) ;; => (1 4)
To find just the last such index, use last on this result. While it is possible to use reverse on the input, it does not offer any performance benefit for this problem.
The logic of forming pairs of numbers and comparing each number to the next number in the sequence can be factored out in a transducer that does not care about whether you want your result in the form of a vector with all indices or just the last index. Forming pairs can be done using partition as already suggested in the other answers, but I did not find a transducer implementation of that function, which would greatly facilitate. Here is a workaround that uses a mapping transducer along with some mutable state.
(defn indexed-pairs []
(let [s (atom [-2 nil nil])]
(comp (map #(swap! s (fn [[i a b]] [(inc i) b %])))
(remove (comp neg? first)))))
(defn indices-of-pairs-such-that [f]
(comp (indexed-pairs)
(filter (fn [[i a b]] (f a b)))
(map first)))
In this code, the function indices-of-pairs-such-that will return a transducer that we can use in various ways, for instance with into to produce a vector of indices:
(into [] (indices-of-pairs-such-that <) [1 1 2 2 1 2])
;; => [1 4]
Or, as was asked in the question, we can use tranduce along with a reducing function that always picks the second argument if we only want the last index:
(transduce (indices-of-pairs-such-that <) (completing (fn [a b] b)) nil [1 1 2 2 1 2])
;; => 4
This is the power of transducers: they decouple sequence algorithms from the results of those algorithms. The function indices-of-pairs-such-that encodes the sequence algorithm but does not have to know whether we want all the indices or just the last index.
The general problem can be solved with ...
(defn indexes-of-pairs [p coll]
(let [check-list (map (fn [i x rx] (when (p x rx) i)) (range) coll (rest coll))]
(filter identity check-list)))
... which returns the indexes of adjacent pairs of a sequence coll that are related by predicate p. For example,
(indexes-of-pairs < [1 1 2 2 1 2])
=> (1 4)
For your example, you can define
(def with-keep-indexed (partial indexes-of-pairs <))
Then
(with-keep-indexed [1 1 2 2 1 2])
=> (1 4)
There are many ways to solve a problem. Here are two alternatives, including a unit test using my favorite template project. The first one uses a loop over the first (N-1) indexes in an imperative style not so different than what you'd write in Java:
(ns tst.demo.core
(:use tupelo.core tupelo.test))
(defn step-up-index-loopy
[xs] ; a sequence of "x" values
(let-spy
[xs (vec xs) ; coerce to vector in case we get a list (faster)
accum (atom []) ; an accumulator
N (count xs)]
(dotimes [i (dec N)] ; loop starting at i=0
(let-spy [j (inc i)
ival (get xs i)
jval (get xs j)]
(when (< ival jval)
(swap! accum conj i))))
#accum))
When run, it produces this output:
calling step-up-index-loopy
xs => [1 1 2 2 1 2]
accum => #object[clojure.lang.Atom 0x4e4dcf7c {:status :ready, :val []}]
N => 6
j => 1
ival => 1
jval => 1
j => 2
ival => 1
jval => 2
j => 3
ival => 2
jval => 2
j => 4
ival => 2
jval => 1
j => 5
ival => 1
jval => 2
The second one uses a more "functional" style that avoids direct indexing. Sometimes this makes things simpler, but sometimes it can appear more complicated. You be the judge:
(defn step-up-index
[xs] ; a sequence of "x" values
(let-spy-pretty
[pairs (partition 2 1 xs)
pairs-indexed (indexed pairs) ; append index # [0 1 2 ...] to beginning of each pair
reducer-fn (fn [accum pair-indexed]
; destructure `pair-indexed`
(let-spy [[idx [ival jval]] pair-indexed]
(if (< ival jval)
(conj accum idx)
accum)))
result (reduce reducer-fn
[] ; initial state for `accum`
pairs-indexed)]
result))
The function indexed is from the Tupelo Clojure library.
When you run the code you'll see:
calling step-up-index
pairs =>
((1 1) (1 2) (2 2) (2 1) (1 2))
pairs-indexed =>
([0 (1 1)] [1 (1 2)] [2 (2 2)] [3 (2 1)] [4 (1 2)])
reducer-fn =>
#object[tst.demo.core$step_up_index$reducer_fn__21389 0x108aaf1f "tst.demo.core$step_up_index$reducer_fn__21389#108aaf1f"]
[idx [ival jval]] => [0 [1 1]]
[idx [ival jval]] => [1 [1 2]]
[idx [ival jval]] => [2 [2 2]]
[idx [ival jval]] => [3 [2 1]]
[idx [ival jval]] => [4 [1 2]]
result =>
[1 4]
Both of them work:
(dotest
(newline)
(println "calling step-up-index-loopy")
(is= [1 4]
(step-up-index-loopy [1 1 2 2 1 2]))
(newline)
(println "calling step-up-index")
(is= [1 4]
(step-up-index [1 1 2 2 1 2])))
With results:
-----------------------------------
Clojure 1.10.3 Java 15.0.2
-----------------------------------
Testing tst.demo.core
Ran 2 tests containing 2 assertions.
0 failures, 0 errors.
The form let-spy is from the Tupelo Clojure library, and makes writing & debugging things easier. See the docs for more info. When satisfied everything is working, replace with
let-spy => let
Also be sure to study the list of documentation sources included in the template project, especially the Clojure CheatSheet.
Another solution using keep-indexed is pretty short:
(defn step-up-index
[xs]
(let [pairs (partition 2 1 xs)
result (vec
(keep-indexed
(fn [idx pair]
(let [[ival jval] pair]
(when (< ival jval)
idx)))
pairs))]
result))
(dotest
(is= [1 4] (step-up-index [1 1 2 2 1 2])))

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)

Why am I getting a StackoverflowError on a function without explicit recursion

I am trying to generate a relatively small (1296 elements) list of vectors essentially enumerating 4 base 6 digits from [0 0 0 0] to [5 5 5 5]
[0 0 0 0], [1 0 0 0] ... [5 0 0 0], [0 1 0 0] ... [5 5 5 5]
Currently what I have is:
(letfn [(next-v [v]
(let [active-index (some (fn [[i e]] (when (> 5 e) i))
(map-indexed vector v))]
(map-indexed #(cond
(> active-index %1) 0
(= active-index %1) (inc %2)
:else %2)
v)))]
(last (take 1290 (iterate next-v [0 0 0 0]))))
This works but it eventually blows the stack.
What am I doing here that causes the StackOverflowError?
How can I structure my code so that it is "safe"?
Is there a better way of doing what I am trying to do?
The way I would solve this is:
(def my-range
(for [i (range 0 6)
j (range 0 6)
x (range 0 6)
y (range 0 6)]
[i j x y]))
(nth my-range 1295) ;;=> [5 5 5 5]
Generalized:
(defn combine [coll]
(for [i (range 6)
j coll]
(conj j i)))
(combine (map list (range 6)))
(combine (combine (map list (range 6))))
(combine (combine (combine (map list (range 6)))))
(def result (nth (iterate combine (map list (range 6))) 3))
This is due to lazyiness in the iterated function body. Notice that the result returned by the first call of next-v is passed to next-v again, before being evaluated (because its a lazy seq), then next-v returns again an unevaluated lazy-seq which will again be passed to it.
When you realize the final lazy seq, to produce the first element all the chained seqs have to be realized to get through to your initial [0 0 0 0]. This will blow the stack.
Stuart Sierra wrote a nice article on this with more examples: http://stuartsierra.com/2015/04/26/clojure-donts-concat
You could simply wrap the map-indexed call in the let body in a vec.
Finding a more generic algorithm to your problem is recommended though.

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.

How To Capture "Row" Number

My question is how can I capture the index of the vector row where a match occurred? In the code below, what am I doing wrong?
I have a vector of vectors
(def v1 [[44 2 3 4 5][1 6 7 5 10][11 12 13 14 15]])
a column index, and a comparison value
(def cmp-val1 11)
(def col-idx 0)
I want to return the row index where a comparison returned true. With col-idx = 0 and cmp-val1 = 11, I should see (first row-num) return 2, and it is returning 1.
(defn ret-match-row
"Return the index of the row, in which the cmp-val is found.
It is okay to increment 0."
[in-seq cmp-val col-idx]
(let [rn 0]
(let [row-num
(for [seq-row in-seq
:let [local-row-num (inc rn)]
:when (= cmp-val (nth seq-row col-idx nil))]
local-row-num)]
(first row-num))))
From lein repl:
bene-csv.core=> (ret-match-row v1 cmp-val1 col-idx)
1
=> (defn ret-match-row
[coll cmp idx]
(keep-indexed (fn [i v] (if (= cmp (get v idx)) i)) coll))
=> (ret-match-row v1 11 0)
(2)
A flexible answer comes from separating this into three distinct problems and composing them.
creating the data you seek
finding the data you want
presenting the way it should look.
first we number the rows by adding row numbers to them
(map vector v1 (range))
then filter out the rows not containing the number you want:
(filter (fn [[data index]] (some #{11} data)) (map vector v1 (range)))
> ([[11 12 13 14 15] 2])
here i used the trick that sets are functions that test their input for inclusion in the set which allows this to test for multiple values:
(filter (fn [[data index]] (some #{11 44} data)) (map vector v1 (range)))
> ([[44 2 3 4 5] 0] [[11 12 13 14 15] 2])
then since you only want to know where it matched and not what matched we filter that out:
(map second (filter (fn [[data index]] (some #{11 44} data)) (map vector v1 (range))))
> (0 2)
to wrap this into a nice function we write out the steps:
(defn with-row-numbers [col] (map vector col (range)))
(defn find-my-rows [rows goals]
(filter (fn [[data index]] (some (set goals) data)) rows))
(defn present-rows [rows] (map second rows))
and then compose them:
(defn ret-match-row [data rows]
(-> data
(with-row-numbers)
(find-my-rows rows)
(present-rows)))
(ret-match-row v1 [11])
(2)
sorry i couldn't help making it work with multiple values, its a habit.
(ret-match-row v1 [11 15 44])
> (0 2)
There may be other ways to do what your'e asking, but you can use a loop/recur to achieve the iteration you're after:
(defn ret-match-row [rows val col-idx]
(loop [[row & rows] rows
pos 0]
(cond
(not row)
nil
(= val (nth row col-idx))
pos
:not-found
(recur rows (inc pos)))))
(ret-match-row [[44 2 3 4 5]
[1 6 7 8 10]
[11 12 13 14 15]]
11
0)
;; => 2
You're also running into Clojure's immutability - the (inc rn) is not actually modifying rn. The loop / recur solution uses inc as well, but it passes the result of inc to the next iteration of the loop.
Clojure's for (list comprehension) form also will loop over all of the values in the sequence, resulting in a new sequence -- which is most likely not what you want. Even if you made the for loop do what you want, it will find all the matches, not just the first. The loop / recur example stops at the first match.
My take, using
clojure.contrib.seq find-first, indexed:
(defn ret-match-row [rows val col-idx]
(first
(find-first #(= val (nth (second %) col-idx))
(indexed rows))))