2017-05-23 6 views
0

verschmelzen Ich habe ein Array von Arrays wie folgt: [['Area1', 12345], ['Area2', 54321]].Array von Arrays in Rails

Also, wenn ich an das bestehende Array hinzufügen wird dieses Array ['Area1', 33441] Ich möchte entweder das Array wie diese [['Area1', 12345, 33441], ['Area2', 54321]] zu fusionieren oder die Informationen wie folgt angezeigt:

Area1: 12345, 33441 Area2: 54321

Hat jemand eine Idee haben, wenn ist das in Schienen möglich? Vielen Dank!

+1

Scheint wie ein Hash könnte die geeignetere Datenstruktur hier sein. – meagar

Antwort

4

Sie Hash#merge! Verfahren mit einem Block dafür verwenden könnte:

initial = [['Area1', 12345], ['Area2', 54321]].to_h 
initial.merge!({'Area1' => 1212 }) { |_,v1,v2| [v1,v2].flatten } 
#=> {"Area1"=>[12345, 1212], "Area2"=>54321} 

und wenn Sie das Ergebnis sein wollen ein Array ist, können Sie

initial.merge!({'Area1' => 1212 }) { |_,v1,v2| [v1,v2].flatten }.to_a 
+0

Ja, das ist perfekt für meinen Fall. Vielen Dank @xlembouras! – Lucasio

+0

Ich erwarte, dass der Rückgabewert einfacher wäre, wenn '" Area2 "=> 54321'" Area2 "=> [54321]' wäre (um mit Arrays aus zwei oder mehr Werten konsistent zu sein). Zum Beispiel: initial = [['Area1', 12345], ['Area2', 54321]]; (initial + [['Area1', 1212]]). each_with_object ({}) {| (Bereich, nbr), h | h.merge! (area => [nbr]) {| _, v1, v2 | v1 + v2}} # => {"Area1" => [12345, 1212], "Area2" => [54321]} '. (Leser: Sowohl die x-Antwort als auch diese Variante verwenden die Form [Hash # merge!] (Http://ruby-doc.org/core-2.4.0/Hash.html#method-i-merge-21), die verwendet wird ein Block, um die Werte von Schlüsseln zu berechnen, die in beiden Hashwerten vorhanden sind.) –

0

Sie verwenden wahrscheinlich nicht die richtige Datenstruktur. Sie sind besser, einen Hash für den Zweck der Verwendung, die wie folgt aussieht:

areas = { 
    'Area1' => [12345], 
    'Area2' => [54321] 
    } 

Aber nach oben Ihre Struktur, die Sie so etwas tun kann:

areas = [['Area1', 12345], ['Area2', 54321]] 
    new_area = ['Area1', 33441] 

    areas.map { |area| 
    if area.first == new_area.first 
     area + [new_area.last] 
    else 
     area 
    end 
    end 

Auch nur so ist es für Sie einfacher zu finde dies in der Zukunft, das hat nichts mit Rails zu tun (das Web-Framework, das auf Ruby sitzt), sondern mit Ruby selbst (der Programmiersprache).

0

Wenn Sie mit haften würde verwenden möchten versuchen Arrays, dann so etwas wie:

arr1 = [['Area1', 12345], ['Area2', 54321]] 
arr2 = ['Area1', 33441] 
arr1.inject([]){|r,i| r.push(i[0] == arr2[0] ? i.push(arr2[1]) : i)} 

In Konsole:

012.351.
2.3.1 :001 > arr1 = [['Area1', 12345], ['Area2', 54321]] 
=> [["Area1", 12345], ["Area2", 54321]] 
2.3.1 :002 > arr2 = ['Area1', 33441] 
=> ["Area1", 33441] 
2.3.1 :003 > arr1.inject([]){|r,i| r.push(i[0] == arr2[0] ? i.push(arr2[1]) : i)} 
=> [["Area1", 12345, 33441], ["Area2", 54321]] 

bei polmiro Antwort sucht, ziehe ich seine map meiner inject. Sie sind im Wesentlichen die gleichen, glaube ich. Nur dass map die Arbeit für Sie erledigt, eine neue array zu erstellen, während Sie mit inject die neue array übergeben müssen. Und map macht eine implizite push, während, mit inject, wiederum müssen Sie die Arbeit selbst tun. Netter Job, Polmiro!

Hier ist die einzeilige Version seiner Antwort (wenn Sie mögen diese Art der Sache):

arr1.map{|a| a[0] == arr2[0] ? a << arr2[1] : a} 

Und wieder in der Konsole:

2.3.1 :001 > arr1 = [['Area1', 12345], ['Area2', 54321]] 
=> [["Area1", 12345], ["Area2", 54321]] 
2.3.1 :002 > arr2 = ['Area1', 33441] 
=> ["Area1", 33441] 
2.3.1 :003 > arr1.map{|a| a[0] == arr2[0] ? a << arr2[1] : a}  
=> [["Area1", 12345, 33441], ["Area2", 54321]]  
0

Für

arr = [['Area1', 12345], ['Area2', 54321]] 
to_add = ['Area1', 1212] 

Wir können das gewünschte Array wie folgt berechnen:

(arr + [to_add]).group_by(&:first).map { |k,v| [k, *v.map(&:last)] } 
    #=> [["Area1", 12345, 1212], ["Area2", 54321]] 

Der erste Schritt, Enumerable#group_by Verwendung erzeugt die folgende hash:

(arr + [to_add]).group_by(&:first) 
    #=> {"Area1"=>[["Area1", 12345], ["Area1", 1212]], 
    # "Area2"=>[["Area2", 54321]]} 

Dafür wir sicher sein müssen zu arbeiten, dass group_by einen Hash, dessen Schlüssel erzeugt sind die gleichen wie arr.map(&:first).uniq #=> ["Area1", "Area2"] bestellt. (Beachten Sie, dass Array#uniq die Reihenfolge beibehält, indem die erste Instanz jedes Elements beibehalten wird). Siehe this SO question. Da Array#each die Elemente arr + [to_add] der Reihe nach generiert und die Reihenfolge der Hash-Schlüssel für Ruby-Versionen 1.9+ beibehalten wird, können wir sicher sein, dass das Ergebnis Elemente in der richtigen Reihenfolge enthält.

Andere haben argumentiert, dass das Darstellen der Daten als Hash ein besseres Datenmodell sein könnte. Das mag sein, aber die Frage liefert nicht genügend Informationen darüber, wie der Rückgabewert verwendet werden soll, um sicher zu sein. Ich habe daher nur das zur Verfügung gestellt, was in der Frage gestellt wurde.