Ruby Array find_first Objekt?

135

Vermisse ich etwas in der Array-Dokumentation? Ich habe ein Array, das bis zu einem Objekt enthält, das ein bestimmtes Kriterium erfüllt. Ich möchte dieses Objekt effizient finden. Die beste Idee, die ich aus den Dokumenten habe, ist folgende:

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

Aber ich bin aus zwei Gründen unzufrieden:

  1. Das selecthat mich dazu gebracht, das ganze Array zu durchqueren, obwohl wir nach dem ersten Treffer hätten aussteigen können.
  2. Ich brauchte eine Codezeile (mit einer Bedingung), um die Kandidaten zu reduzieren.

Beide Operationen sind verschwenderisch mit dem Vorwissen, dass es 0 oder 1 zufriedenstellende Objekte gibt.

Was ich möchte, ist so etwas wie:

array.find_first(block)

Dies gibt nil oder das erste Objekt zurück, für das der Block true ergibt, und beendet die Durchquerung an diesem Objekt.

Muss ich das selbst schreiben? All diese anderen großartigen Methoden in Array lassen mich denken, dass es da ist und ich sehe es einfach nicht.

der Blechmann
quelle

Antworten:

201

Entweder verstehe ich Ihre Frage nicht, oder Enumerable # find ist das , wonach Sie gesucht haben.

Mladen Jablanović
quelle
32
Kein Problem, ich finde es auch oft ärgerlich, dass in der Ruby-Dokumentation nicht alle geerbten oder enthaltenen Klassen und Module aufgelistet sind.
Mladen Jablanović
4
Weitere Informationen: Die [1,2,3,5,2].find { |n| puts n; n == 2 } Iteration wird beendet, sobald das erste übereinstimmende Element gefunden wurde.
RajuGT
97

Verwenden Sie die Array- detectMethode, wenn Sie den ersten Wert zurückgeben möchten, wobei block true zurückgibt

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

OR

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

Wenn Sie alle Werte zurückgeben möchten, bei denen block true zurückgibt, verwenden Sie select

[1,2,3,11,34].select(&:even?)  #=> [2, 34]
Sandip Ransing
quelle
5
.detectist genau das, was ich brauche. Aber was ist dann der Unterschied .find?
Augustin Riedinger
13
@ AugustinRiedinger kein Unterschied, beide sind gleich. detectist nur ein Alias ​​für find ruby-doc.org/core-2.1.2/Enumerable.html#method-i-find
Sandip Ransing
Aus Gründen der Konsistenz folge ich gerne dem Ruby Style Guide , der den Fund bevorzugt
Paul van Leeuwen
20

Vermutlich haben Sie gerade die Suchmethode in den Dokumenten verpasst:

my_array.find {|e| e.satisfies_condition? }
sepp2k
quelle
8
Oder wenn Sie Code-Golf mögen,my_array.find(&:satisfies_condition?)
Andrew Grimm
14

Müssen Sie das Objekt selbst oder brauchen Sie nur zu wissen , ob es ist ein Objekt , das genügt. Wenn erstere dann ja: benutze find:

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

sonst kannst du verwenden any?

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

Letzterer wird mit "wahr" auf Kaution gehen, wenn er eine findet, die die Bedingung erfüllt. Ersteres wird dasselbe tun, aber das Objekt zurückgeben.

Taryn East
quelle