2016-04-01 16 views
1

Ich suche nach einem Element in source, das eine Bedingung erfüllt. Die Bedingung ist oft, aber nicht immer, ein Regexp-Match. Ich bin auf der Suche nach einer Version von find, die das Ergebnis der Bedingung, nicht das ursprüngliche Element zurückgibt. Mit find muss ich das Kriterium für das erfolgreiche Element neu berechnen.Ein `find`, das den Zustandswert zurückgibt, nicht den Elementwert

Das Beste, was ich in dieser Richtung gearbeitet läuft:

source.find {|e| if (m = e.match(/(e.)/)); break m[0]; end} 

Um Semikolons Aufforderung Rubocop zu bemängeln mehreren Anweisungen Linien zu vermeiden, ziehe ich es zu schreiben, wie folgt:

source.find {|e| break m[0] if (m = e.match(/(e.)/))} 

Aber Rubin kann nicht mit der Vorwärtsreferenz umgehen (und ich bin nicht verdreht genug, um e für m wiederzuverwenden).

Gibt es etwas Eleganteres, um diese Aufgabe mit dem Kurzschnitt zu erledigen?

+0

Falls Sie es nicht wussten, können Sie die Antworten aufwerten und den am meisten hilfreichen auswählen. –

Antwort

1

Da Sie break haben, brauchen Sie nicht find zu brechen. Verwenden Sie each.

source.each {|e| m = e[/e./] and break m} 
+1

Zu vertieft mit "finden" und "injizieren" Cleverness. Vielen Dank. –

0

Obwohl ich lieber etwas @sawa schon sagt, können Sie eine Instanz-Variable verwenden:

["dog", "cat", "emu", "pig"].find { |e| $da_match = e[/(e.)/] } 
    #=> "emu" 
$da_match 
    #=> "em" 

oder für Ihren regex:

["dog", "cat", "emu", "pig"].find { |e| e =~ /(e.)/ } 
    #=> "emu" 
$1 
    #=> "em" 

Wenn der reguläre Ausdruck r nicht (oder vielleicht nicht) eine äußere Erfassungsgruppe haben, könnten Sie eine wie folgt hinzufügen: /(#{r})/. Zum Beispiel

r0 = /e./ 
r1 = /(#{r0})/ 
    #/((?-mix:e.))/ 

["dog", "cat", "emu", "pig"].find { |e| e =~ r1 } 
    #=> "emu" 
$1 
    #=> "em" 

Je nachdem, wie der Regex verwendet wird, kann dies nicht funktionieren. Wenn die (ursprüngliche) Regex eine oder mehrere Capture-Gruppen enthält, wird die Capture-Gruppe 1 zur Capture-Gruppe 2 und so weiter. Wenn der Inhalt einer dieser Fanggruppen in der Regex oder im nachfolgenden Code referenziert wird, würde daher ein falscher Wert erhalten. Dies wäre kein Problem sein, aber wenn Sie Capture-Gruppen mit den Namen verwendet und reserviert einen Namen für äußere hinzugefügt wird:

["dog", "cat", "emu", "pig"].find { |e| e =~ /(?<outer>#{/e./})/ } 
    #=> "emu" 
$~[:outer] 
    #=> "em" 

$~ ist eine globale Variable die letzte MatchData Objekt enthält.