2017-03-07 3 views
0

Ich bin neu in der Programmierung und verwende Ruby, um mit Syntax und Kontrollfluss vertraut zu werden.Finden Sie alle maximalen Werte in einem Array von Hashes und speichern Sie sie dann in einem separaten Array. Ruby

Das Programm, an dem ich gerade arbeite, möchte, dass ich den DVD-Namen einstelle, der die längste Spielzeit hat. Hier ist mein Code:

dvds = [ 
    { 
    :dvd_name=>"x-men", 
    :dvd_playing_time=>549, 
    :times_played=>9.0 
    }, 
    { 
    :dvd_name=>"Pi", 
    :dvd_playing_time=>549, 
    :times_played=>6.0 
    } 
] 

Beide Hashes haben dvd_playing_time von 549, so möchte ich sowohl "x-men" und "Pi" in einem Array gespeichert. Ich habe versucht max_by, aber es gibt nur eine dvd_name zurück.

dvds.max_by { |length| length[:dvd_playing_time]}[:dvd_name] 

Jede Hilfe, die Sie zur Verfügung stellen können, ist fantastisch!

+1

Es wäre klarer gewesen, den Schlüssel ': dvd_length' ': dvd_playing_time' gemacht zu haben, da einige Leser, vor allem diejenigen, für die Englisch eine zweite Sprache ist, denken, dass Sie sich auf': times_played' beziehen. Außerdem wäre es besser gewesen, die Werte von ': times_played' für die beiden Hashes unterschiedlich zu machen. –

+0

Cary Swoveland, vielen Dank für Ihren Vorschlag. Ich werde mein Symbol modifizieren, um klarer zu sein, als es jetzt ist. – aprogrammer

+0

Ich habe bearbeitet: dvd_length zu: dvd_playing_time und auch geändert: times_played Werte unterschiedlich. – aprogrammer

Antwort

3

Es gibt drei Schritte, um eine Antwort zu erhalten.

  • die längste Spielzeit bestimmen, indem Enumerable#map ing jeder Hash-h-h[:dvd_length] und dann die Enumerable#max dieser Werte nehmen.
  • Verwenden Sie Hash#select, um die Hashes h auszuwählen, für die der maximalen Spielzeit entspricht.
  • Enumerable#map diese Hashes h mit der maximalen Spielzeit zu h[:dvd_name].

length_of_longest = dvds.map { |h| h[:dvd_length] }.max 
    #=> 549 
puts dvds.select { |h| h[:dvd_length] == length_of_longest }.map { |h| h[:dvd_name] } 
    # x-men 
    # Pi 
+0

Vielen Dank! Dein Code hat gut funktioniert. – aprogrammer

1

Wenn Sie es in einer Zeile zu tun:

dvds.group_by{ |dvd| dvd[:dvd_playing_time] }.max.last.map{ |dvd| dvd[:dvd_name] } 

Dieser Codegruppen die dvds durch Länge, nimmt die Gruppe mit der max Länge, und ordnet sie enthalten nur die DVD-Namen. Es ist nicht die schnellste Option, da es das Array ein paar Mal durchlaufen wird (n + g + m-mal, technisch).

Wenn Sie Geschwindigkeit betroffen sind:

max = 0 
longest = [] 
dvds.each do |dvd| 
    if dvd[:dvd_playing_time] > max 
    max = dvd[:dvd_playing_time] 
    longest = [dvd[:dvd_name]] 
    elsif dvd[:dvd_playing_time] == max 
    longest << dvd[:dvd_name] 
    end 
end 

Dieser Algorithmus, während unelegant, geben Sie die Antwort mit einer einzigen Iteration durch das Array, das das Beste ist, was Sie tun können.

+0

Sehr nette Antwort. 1) Es ist vielleicht erwähnenswert (bei der Diskussion von # 2), dass # 1 zwischen 2 und 3 Durchläufen durch das Array erfordert. 2) Während "max" in # 1 in Ordnung ist, könnte 'max_by (&: first)' klarer sein. 3) In # 2 könnten Sie 'dvds.each_with_object ([]) do | dvd, am längsten | schreiben ... 'damit Sie am Ende nicht' longest' hinzufügen müssen, wenn Sie es beispielsweise in eine Methode umbrechen. –

+0

@CarySwoveland Weißt du, ob each_with_object in Ordnung sein wird, wenn ich einen neuen Verweis auf "longest" übergebe, wenn ein neues Maximum gefunden wird und das alte Array verworfen werden muss? Ich war besorgt, dass es mich zwingen würde, das gleiche Array zu verwenden, das langsamer wäre. – eiko

+0

Es ist kein Problem der Geschwindigkeit. Es funktioniert einfach nicht mit 'longest = [dvd [: dvd_name]]' wenn 'longest' eine Blockvariable ist. (Die Zuweisung ändert "längste" 'object_id'.) In diesem Fall benötigen Sie' longest.replace ([dvd [: dvd_name]]) '. ('längste << DVD [: dvd_name]' ist in Ordnung.) Außerdem haben Sie einen Tippfehler: die rechte Klammer in 'dvd [: dvd_length == max]' ist falsch platziert. –

Verwandte Themen