Ruby Array find_first object?

135

Czy brakuje mi czegoś w dokumentacji tablicy? Mam tablicę, która zawiera maksymalnie jeden obiekt spełniający określone kryterium. Chciałbym sprawnie znaleźć ten obiekt. Najlepszy pomysł, jaki mam z dokumentów, jest następujący:

candidates = my_array.select { |e| e.satisfies_condition? }
found_it = candidates.first if !candidates.empty?

Ale jestem niezadowolony z dwóch powodów:

  1. To selectsprawiło, że przeszedłem przez całą tablicę, mimo że mogliśmy się wycofać po pierwszym trafieniu.
  2. Potrzebowałem linii kodu (z warunkiem), aby spłaszczyć kandydatów.

Obie operacje są marnotrawstwem, ponieważ wiadomo, że istnieje 0 lub 1 zadowalających obiektów.

Chciałbym coś takiego:

array.find_first(block)

co zwraca nil lub pierwszy obiekt, dla którego blok zwraca wartość true, kończąc przemierzanie w tym obiekcie.

Czy muszę sam to napisać? Wszystkie te inne świetne metody w Array sprawiają, że myślę, że tam jest i po prostu tego nie widzę.

Blaszany Człowiek
źródło

Odpowiedzi:

201

Albo nie rozumiem twojego pytania, albo Enumerable # find jest tym, czego szukałeś.

Mladen Jablanović
źródło
32
Żaden problem, często denerwuje mnie również to, że dokumentacja Rubiego nie zawiera listy metod wszystkich dziedziczonych lub dołączonych klas i modułów.
Mladen Jablanović
4
więcej informacji: [1,2,3,5,2].find { |n| puts n; n == 2 } iteracja zatrzymuje się, gdy znajdzie pierwszy pasujący element.
rajuGT
97

użyj detectmetody tablicowej , jeśli chcesz zwrócić pierwszą wartość, gdzie blok zwraca prawdę

[1,2,3,11,34].detect(&:even?) #=> 2

OR

[1,2,3,11,34].detect{|i| i.even?} #=> 2

Jeśli chcesz zwrócić wszystkie wartości, dla których blok zwraca prawdę, użyj select

[1,2,3,11,34].select(&:even?)  #=> [2, 34]
Sandip Ransing
źródło
5
.detectjest dokładnie tym, czego potrzebuję. Ale jaka jest w tym różnica .find?
Augustin Riedinger
13
@AugustinRiedinger bez różnicy, oba są takie same. detectto tylko alias do find ruby-doc.org/core-2.1.2/Enumerable.html#method-i-find
Sandip Ransing
dla pewnej spójności lubię postępować zgodnie z Przewodnikiem po stylu Ruby , który sprzyja znajdowaniu
Paul van Leeuwen,
20

Chyba właśnie przegapiłeś metodę find w dokumentach:

my_array.find {|e| e.satisfies_condition? }
sepp2k
źródło
8
Lub jeśli lubisz gry w code-golfa,my_array.find(&:satisfies_condition?)
Andrew Grimm,
14

Czy trzeba samego obiektu czy po prostu trzeba wiedzieć, jeśli nie jest obiektem, który spełnia. Jeśli pierwszy, to tak: użyj find:

found_object = my_array.find { |e| e.satisfies_condition? }

w przeciwnym razie możesz użyć any?

found_it = my_array.any?  { |e| e.satisfies_condition? }

Ten ostatni wyświetli „prawda”, gdy znajdzie taki, który spełnia warunek. Pierwsza zrobi to samo, ale zwróci obiekt.

Taryn East
źródło