2

I want to check whether any element in a list satisfies given condition. I have tried using some, which returns either true or nil, but can't seem to find a function with similar functionality that would retrieve true/false.

Example - checking whether there is a 6 in a list:

(some #(= 6 %) numbers-list))

zmaten
  • 429
  • 4
  • 16
  • 4
    Would calling `(boolean (some ...))` work? – Rulle Jun 14 '23 at 11:59
  • 1
    It does, but I find at a bit cumbersome and I'm wondering if the same can be achieved with a single function – zmaten Jun 14 '23 at 12:24
  • 3
    `some` doesn't even return true or nil. It returns nil, or the first truthy result of `(f x)`, where `x` is from the input sequence. So `(some #{1 2 3} xs)` tells you whether 1, 2, or 3 occurs first in the list. – amalloy Jun 14 '23 at 13:02
  • 2
    The reason calling `boolean` feels cumbersome is that there is generally no need to. The values returned by `some` are truthy or falsy, and that is idiomatic Clojure, you can use them as they are, it’s just a matter of getting used to it. If you are using Java interop with something that needs an actual boolean vallue, the compiler will generally take care of that for you. – James Elliott Jun 14 '23 at 14:52

3 Answers3

5

This is I think the most idiomatic approach (using set as function), but this does return nil or the value itself:

(some #{6} [1 2 3 4 5 6 7])
;; => 6

As mentioned in a comment on your question, this can be converted to boolean using boolean.

Other approach that returns boolean is by converting to a set and using contains? you return a boolean:

(contains? (set [1 2 3 4 5 6 7]) 6)
;; => true

(since contains "for numerically indexed collections like vectors and Java arrays, ... tests if the numeric key is within the range of indexes.") Does need extra conversion.

Or similarly using Java interop (but working on vector and list as well):

(.contains [1 2 3 4 5 6 7] 6)
;; => true

Also see Test whether a list contains a specific value in Clojure.

user2609980
  • 10,264
  • 15
  • 74
  • 143
1

I had a similar desire some years ago and wrote the function has-some? for this purpose, along with it's inverse has-none?. From the unit tests:

(verify
  (is= true  (t/has-some? odd? [1 2 3]))
  (is= false (t/has-some? odd? [2 4 6]))
  (is= false (t/has-some? odd? []))

  (is= false (t/has-none? odd? [1 2 3]))
  (is= true  (t/has-none? odd? [2 4 6]))
  (is= true  (t/has-none? odd? [])))

The purpose of these functions is to remove the ambiguity between the some and some? functions, as well as the crazy (IMHO) conflict between the meaning of not-any? vs any?. Both of these conflicts in clojure.core make it very easy to shoot yourself in the foot.

Alan Thompson
  • 29,276
  • 6
  • 41
  • 48
1

to me it's also weird, that there is no any? in a sense of 'has-any?' in clojure.

Though there is not-any? there. So you just complement it and you have what you need

user> (def has-any? (complement not-any?))
#'user/has-any?

user> (has-any? #(= % 6) [1 2 3 4 5 6])
true

user> (has-any? #(= % 6) [1 2 3 4 5])
false

user> (has-any? #(= % 6) [])
false
leetwinski
  • 17,408
  • 2
  • 18
  • 42
  • Reasoning of [`any?`](https://clojuredocs.org/clojure.core/any_q) by Alex Miller on [Ask Clojure](https://ask.clojure.org/index.php/11260/does-the-any-function-have-the-correct-behavior?show=11261#a11261): "`any?` is a predicate that is intended to always return true, so yes it is the correct behavior. `any?` was added as a predicate to use with spec in the case where any value is valid. It is not a complement to `not-any?`, despite that obvious assumption. There are, in the end, only so many words and despite a lot of care in this regard, there are times when these confusions exist." – user2609980 Jun 19 '23 at 11:58