выбрать первый элемент коллекции, который удовлетворяет заданному предикату в clojure

18

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

, например:

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

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

    
задан szymanowski 04.12.2013 в 16:26
источник

2 ответа

32

Существует несколько возможностей.

some

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

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

filter + first

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

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

remove + first

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

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

Или с some :

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

Так вот, я думаю.

    
ответ дан xsc 04.12.2013 в 16:38
источник
  • отлично! Спасибо! –  szymanowski 04.12.2013 в 17:09
  • рад, что я мог бы помочь! (хотя другой ответ был опубликован около 20 секунд до моего) –  xsc 04.12.2013 в 17:15
  • Предостережение - (сначала (фильтр ...)) является более строгим (и быстрым, поскольку фильтр возвращает ленивую последовательность), потому что использование некоторых является неоднозначным - рассмотрим (некоторые # (когда (nil?%)%) Используя некоторые, найдет первый элемент non-nil. –  djhaskin987 11.02.2016 в 06:14
  • @ djhaskin987 Это правда, что если вы используете кого-то, чтобы найти элемент nil, вы пройдете всю последовательность (и, следовательно, потенциально никогда не закончите), - в других случаях он будет реализовывать только ленивые секвенции, насколько это необходимо. Обратите внимание, однако, что мое описание некоторых уже содержит не-нильскую часть, которую вы подчеркиваете. :) –  xsc 11.02.2016 в 16:16
8

Использовать фильтр и сначала

user=> (->> (range) (filter #(> % 10)) first)
11
user=> (first (filter #(> % 10) (range)))
11
    
ответ дан edbond 04.12.2013 в 16:38
источник
  • без ленивой оценки - это неэффективно? –  Joseph Garvin 16.02.2018 в 15:45
  • @JosephGarvin уверен, диапазон и фильтр ленивы. Без ленивого диапазона оценки потребуется бесконечное время. –  edbond 17.02.2018 в 16:38