2013-12-04 4 views
18

Есть ли функция в clojure, которая (учитывая предикат и коллекцию), выбирает первый элемент, который удовлетворяет заданному предикату и останавливает итерацию?выберите первый элемент коллекции, который удовлетворяет заданному предикату в clojure

, например:

(select-first #(> % 10) (range)) 
=> 11 

Если нет, то, может быть, кто-то мог бы намекать мне о идиоматического реализации

ответ

32

Есть несколько возможностей.

some

some возвращает первое значение не-NIL его предикат возвращает.

(some #(when (> % 10) %) (range)) ;; => 11 

filter + first

filter сохраняет те элементы, которые соответствуют предикат, first извлекает первый из них.

(first (filter #(> % 10) (range))) ;; => 11 

remove + first

Если вы хотите, чтобы найти первый элемент, который делает не соответствуют вашим предиката, remove ваш друг:

(first (remove #(<= % 10) (range))) ;; => 11 

Или с some:

(some #(when-not (<= % 10) %) (range)) ;; => 11 

Так вот, вот и все.

+0

отлично! Спасибо! – szymanowski

+1

рад, что я мог помочь! (хотя другой ответ был опубликован около 20 секунд до моего) – xsc

+1

Предостережение - '(first (filter ...))' более строгий (и быстрый, поскольку фильтр возвращает ленивую последовательность), потому что использование 'some' неоднозначно - - рассмотрим '(некоторые # (когда (nil?%)%)'. Использование 'some' найдет первый элемент * non-nil *. – djhaskin987

8

Используйте фильтр и первый

user=> (->> (range) (filter #(> % 10)) first) 
11 
user=> (first (filter #(> % 10) (range))) 
11 
+0

без ленивой оценки это неэффективно? –

+0

@JosephGarvin уверен, диапазон и фильтр ленивы. Без ленивого диапазона оценки потребуется бесконечное время. – edbond

Смежные вопросы