Return first item in a map/list/sequence that satisfies a predicate - clojure

I am looking for a function that returns the first element in a sequence for which an fn evaluates to true. For example:
(first-map (fn [x] (= x 1)) '(3 4 1))
The above fake function should return 1 (the last element in the list). Is there something like this in Clojure?

user=> (defn find-first
[f coll]
(first (filter f coll)))
#'user/find-first
user=> (find-first #(= % 1) [3 4 1])
1
Edit: A concurrency. :) No. It does not apply f to the whole list. Only to the elements up to the first matching one due to laziness of filter.

In your case, the idiom is
(some #{1} [1 2 3 4])
How it works: #{1} is a set literal. A set is also a function evaluating to its arg if the arg is present in the set and to nil otherwise. Any set element is a "truthy" value (well, except for a boolean false, but that's a rarity in a set). some returns the return value of the predicate evaluated against the first collection member for which the result was truthy.

I tried several methods mentioned in this thread (JDK 8 and Clojure 1.7), and did some benchmark tests:
repl> (defn find-first
[f coll]
(first (filter f coll)))
#'cenx.parker.strategies.vzw.repl/find-first
repl> (time (find-first #(= % 50000000) (range)))
"Elapsed time: 5799.41122 msecs"
50000000
repl> (time (some #{50000000} (range)))
"Elapsed time: 4386.256124 msecs"
50000000
repl> (time (reduce #(when (= %2 50000000) (reduced %2)) nil (range)))
"Elapsed time: 993.267553 msecs"
50000000
The results show that reduce way may be the most efficient solution as in clojure 1.7.

In 2016 there was a patch submitted to clojure core that added an efficient shortcut for (first (filter pred coll)) idiom, it was called seek.
The implementation avoided problems in herent with both the (first (filter)) and (some #(when (pred))) alternatives. That is, it works efficiently with chunked sequences and plays nice with nil? and false? predicates.
Patch:
(defn seek
"Returns first item from coll for which (pred item) returns true.
Returns nil if no such item is present, or the not-found value if supplied."
{:added "1.9" ; note, this was never accepted into clojure core
:static true}
([pred coll] (seek pred coll nil))
([pred coll not-found]
(reduce (fn [_ x]
(if (pred x)
(reduced x)
not-found))
not-found coll)))
Examples:
(seek odd? (range)) => 1
(seek pos? [-1 1]) => 1
(seek pos? [-1 -2] ::not-found) => ::not-found
(seek nil? [1 2 nil 3] ::not-found) => nil
Eventually the patch was rejected:
Upon review, we've decided that we do not wish to include this. Use of linear search (and in particular nested linear search) leads to poor performance - often it's better to use other kinds of data structures and that's why this functionality has not been included in the past. ~Alex Miller 12/May/17 3:34 PM

I think some is the best tool for the job:
(some #(if (= % 1) %) '(3 4 1))

Using drop-while instead of filter should address "over-application" of f for chunked sequences:
(defn find-first [f coll]
(first (drop-while (complement f) coll)))
;;=> #'user/find-first
(find-first #(= % 1) [3 4 1])
;;=> 1

The way I do this in clojure is sort like you might do it in Scheme.
(defn call-with-found
"Call the given predicate, pred, on successive elements of the collection
until the first time pred returns a truthy value, at which time if-found
is called with that element of the collection, and call-with-found returns
the return value of if-found. If no such element of collection is found
(including if collection is empty) then the value if-not-found (defaulting
to false) is returned."
([pred coll & {:keys [if-found if-not-found]
:or {if-found (constantly true)
if-not-found false}}]
(reduce (fn [_ item]
(if (pred item)
(reduced (if-found item))
if-not-found)) if-not-found coll)))
The function call-with-found is called with a predicate and a collection. We search the collection until we find an element which satisfies the predicate, at which point we call the if-found continuation with that value, else we return the if-not-found value.

Related

Is there a reducing function in Clojure that performs the equivalent of `first`?

I'm often writing code of the form
(->> init
(map ...)
(filter ...)
(first))
When converting this into code that uses transducers I'll end up with something like
(transduce (comp (map ...) (filter ...)) (completing #(reduced %2)) nil init)
Writing (completing #(reduced %2)) instead of first doesn't sit well with me at all. It needlessly obscures a very straightforward task. Is there a more idiomatic way of performing this task?
I'd personally use your approach with a custom reducing function but here are some alternatives:
(let [[x] (into [] (comp (map inc) (filter even?) (take 1)) [0 1])]
x)
Using destructing :/
Or:
(first (eduction (map inc) (filter even?) [0 1])
Here you save on calling comp which is done for you. Though it's not super lazy. It'll realize up to 32 elements so it's potentially wasteful.
Fixed with a (take 1):
(first (eduction (map inc) (filter even?) (take 1) [0 1]))
Overall a bit shorter and not too unclear compared to:
(transduce (comp (map inc) (filter even?) (take 1)) (completing #(reduced %2)) nil [0 1])
If you need this a bunch, then I'd probably NOT create a custom reducer function but instead a function similar to transduce that takes xform, coll as the argument and returns the first value. It's clearer what it does and you can give it a nice docstring. If you want to save on calling comp you can also make it similar to eduction:
(defn single-xf
"Returns the first item of transducing the xforms over collection"
{:arglists '([xform* coll])}
[& xforms]
(transduce (apply comp (butlast xforms)) (completing #(reduced %2)) nil (last xforms)))
Example:
(single-xf (map inc) (filter even?) [0 1])
medley has find-first with a transducer arity and xforms has a reducing function called last. I think that the combination of the two is what you're after.
(ns foo.bar
(:require
[medley.core :as medley]
[net.cgrand.xforms.rfs :as rfs]))
(transduce (comp (map ,,,) (medley/find-first ,,,)) rfs/last init)

How to replace the last element in a vector in Clojure

As a newbie to Clojure I often have difficulties to express the simplest things. For example, for replacing the last element in a vector, which would be
v[-1]=new_value
in python, I end up with the following variants in Clojure:
(assoc v (dec (count v)) new_value)
which is pretty long and inexpressive to say the least, or
(conj (vec (butlast v)) new_value)
which even worse, as it has O(n) running time.
That leaves me feeling silly, like a caveman trying to repair a Swiss watch with a club.
What is the right Clojure way to replace the last element in a vector?
To support my O(n)-claim for butlast-version (Clojure 1.8):
(def v (vec (range 1e6)))
#'user/v
user=> (time (first (conj (vec (butlast v)) 55)))
"Elapsed time: 232.686159 msecs"
0
(def v (vec (range 1e7)))
#'user/v
user=> (time (first (conj (vec (butlast v)) 55)))
"Elapsed time: 2423.828127 msecs"
0
So basically for 10 time the number of elements it is 10 times slower.
I'd use
(defn set-top [coll x]
(conj (pop coll) x))
For example,
(set-top [1 2 3] :a)
=> [1 2 :a]
But it also works on the front of lists:
(set-top '(1 2 3) :a)
=> (:a 2 3)
The Clojure stack functions - peek, pop, and conj - work on the natural open end of a sequential collection.
But there is no one right way.
How do the various solutions react to an empty vector?
Your Python v[-1]=new_value throws an exception, as does your (assoc v (dec (count v)) new_value) and my (defn set-top [coll x] (conj (pop coll) x)).
Your (conj (vec (butlast v)) new_value) returns [new_value]. The butlast has no effect.
If you insist on being "pure", your 2nd or 3rd solutions will work. I prefer to be simpler & more explicit using the helper functions from the Tupelo library:
(s/defn replace-at :- ts/List
"Replaces an element in a collection at the specified index."
[coll :- ts/List
index :- s/Int
elem :- s/Any]
...)
(is (= [9 1 2] (replace-at (range 3) 0 9)))
(is (= [0 9 2] (replace-at (range 3) 1 9)))
(is (= [0 1 9] (replace-at (range 3) 2 9)))
As with drop-at, replace-at will throw an exception for invalid values of index.
Similar helper functions exist for
insert-at
drop-at
prepend
append
Note that all of the above work equally well for either a Clojure list (eager or lazy) or a Clojure vector. The conj solution will fail unless you are careful to always coerce the input to a vector first as in your example.

Given a partially ordered set, remove all smaller items

I'm struggling to find a beautiful, idiomatic way to write a function
(defn remove-smaller
[coll partial-order-fn]
___
)
where partial-order-fn takes two arguments and return -1 0 or 1 is they are comparable (resp. smaller, equal, bigger) or nil otherwise.
The result of remove-smaller should be coll, with all items that are smaller than any other item in coll are removed.
Example: If we defined a partial order such as numbers are compared normally, letters too, but a letter and a number are not comparable:
1 < 2 a < t 2 ? a
Then we would have:
(remove-smaller [1 9 a f 3 4 z])
==> [9 z]
(defn partial-compare [x y]
(when (= (type x) (type y))
(compare x y)))
(defn remove-smaller [coll partial-order-fn]
(filter
(fn [x] (every? #(let [p (partial-order-fn x %)]
(or (nil? p) (>= p 0)))
coll))
coll))
(defn -main []
(remove-smaller [1 9 \a \f 3 4 \z] partial-compare))
This outputs (9 \z), which is correct unless you want the return value to be of the same type as coll.
In practice I might just use tom's answer, since no algorithm can guarantee better than O(n^2) worst-case performance and it's easy to read. But if performance matters, choosing an algorithm that is always n^2 isn't good if you can avoid it; the below solution avoids re-iterating over any items which are known not to be maxes, and therefore can be as good as O(n) if the set turns out to actually be totally ordered. (of course, this relies on transitivity of the ordering relation, but since you call this a partial order that's implied)
(defn remove-smaller [cmp coll]
(reduce (fn [maxes x]
(let [[acc keep-x]
,,(reduce (fn [[acc keep-x] [max diff]]
(cond (neg? diff) [(conj acc max) false]
(pos? diff) [acc keep-x]
:else [(conj acc max) keep-x]))
[[] true], (map #(list % (or (cmp x %) 0))
maxes))]
(if keep-x
(conj acc x)
acc)))
(), coll))
(def data [1 9 \a \f 3 4 \z])
(defn my-fn [x y]
(when (= (type x) (type y))
(compare x y)))
(defn remove-smaller [coll partial-order-fn]
(mapv #(->> % (sort partial-order-fn) last) (vals (group-by type data))))
(remove-smaller data my-fn)
;=> [9 \z]
Potentially the order of the remaining items might differ to the input collection, but there is no order between the equality 'partitions'

Clojure compress vector

I am trying to find a Clojure-idiomatic way to "compress" a vector:
(shift-nils-left [:a :b :c :a nil :d nil])
;=> (true [nil nil :a :b :c :a :d])
(shift-nils-left [nil :a])
;=> (false [nil :a])
(shift-nils-left [:a nil])
;=> (true [nil :a])
(shift-nils-left [:a :b])
;=> (false [:a :b])
In other words, I want to move all of the nil values to the left end of the vector, without changing the length. The boolean indicates whether any shifting occurred. The "outside" structure can be any seq, but the inside result should be a vector.
I suspect that the function will involve filter (on the nil values) and into to add to a vector of nils of the same length as the original, but I'm not sure how to reduce the result back to the original length. I know how to this "long-hand", but I suspect that Clojure will be able to do it in a single line.
I am toying with the idea of writing a Bejeweled player as an exercise to learn Clojure.
Thanks.
I would write it like this:
(ns ...
(:require [clojure.contrib.seq-utils :as seq-utils]))
(defn compress-vec
"Returns a list containing a boolean value indicating whether the
vector was changed, and a vector with all the nils in the given
vector shifted to the beginning."
([v]
(let [shifted (vec (apply concat (seq-utils/separate nil? v)))]
(list (not= v shifted)
shifted))))
Edit: so, the same as what Thomas beat me to posting, but I wouldn't use flatten just in case you end up using some sort of seqable object to represent the jewels.
Maybe this way:
(defn shift-nils-left
"separate nil values"
[s]
(let [s1 (vec (flatten (clojure.contrib.seq/separate nil? s)))]
(list (not (= s s1)) s1)))
A little more low-level approach. It traverses the input seq just once as well as the vector of non-nils once. The two more highlevel approaches traverse the input sequence two times (for nil? and (complenent nil?)). The not= traverses the input a third time in the worst-case of no shift.
(defn compress-vec
[v]
(let [[shift? nils non-nils]
(reduce (fn [[shift? nils non-nils] x]
(if (nil? x)
[(pos? (count non-nils)) (conj nils nil) non-nils]
[shift? nils (conj non-nils x)]))
[false [] []] v)]
[shift? (into nils non-nils)]))
(def v [1 2 nil 4 5 nil 7 8] )
(apply vector (take 8 (concat (filter identity v) (repeat nil))))
This creates a sequence of the non- nil values in the vector using filter and then appends nils to the end of the sequence. This gives the values you want as a sequence and then converts them into a vector. The take 8 ensures that the vector is right size.

Is there a function similar to "andmap" in clojure?

I want to apply a series of tests on my list and make sure that all the tests are passed.
Is there a function similar to "andmap" in Clojure?
You could use every?:
user=> (every? string? '("hi" 1))
false
Here's the documentation on every?.
Clojure 1.3 will add every-pred (and the related some-fn for the "or" version).
clojure.core/every-pred
([p] [p1 p2] [p1 p2 p3] [p1 p2 p3 & ps])
Takes a set of predicates and returns a function f that returns true if all of its
composing predicates return a logical true value against all of its arguments, else it returns
false. Note that f is short-circuiting in that it will stop execution on the first
argument that triggers a logical false result against the original predicates.
A naive implementation might be:
(defn every-pred [& preds] (fn [& args] (every? #(every? % args) preds)))
but the actual implementation will have better performance.
I wrote andmap as a macro which takes predicates as its arguments and builds a function that "wraps an and around the predicates", i.e.,
(andmap integer? odd?)
==>
(fn [x] (and (integer? x)
(odd? x)))
(it doesn't expand to exactly this, but it expands to something equivalent to this)
This has the advantage that it shortcuircuts on the predicates so you can write
(every? (andmap integer? odd?) [1 3 "a string"])
without getting a runtime exception as you would get with Arthurs answer.
Here is the definition of andmap:
(defmacro andmap
([] `(fn [& x#] true))
([p & ps] `(fn [& x#] (and (apply ~p x#)
(apply (andmap ~#ps) x#)))))
It is also possible to define andmap as an function which also short-circuits on it's predicates due to lazyness:
(defn andmap [& ps]
(fn [& x]
(every? true? (map (fn [p] (apply p x)) ps))))
The predicates to andmap can take an arbitrary number of arguments, so it is possible to write
(map (andmap #(and (integer? %1)
(integer? %2))
#(and (odd? %1)
(even? %2))
<)
[1 3 9]
[2 6 "string"])
which evaluates to (true true false).
every? will ask "Does this one function return true for each member of the seq", which is close to what I think you are asking for. An improvement on every? would take a list of functions and ask "Are all these predicates true for every member of this seq".
Here is a first attempt:
(defn andmap? [data tests]
(every? true? (for [d data, f tests]
(f d))))
user> (andmap? '(2 4 8) [even? pos?])
true
user> (andmap? '(2 4 8) [even? odd?])
false