Kombination zweier Arrays in Ruby

82

Was ist der Ruby-Weg, um Folgendes zu erreichen?

a = [1,2]
b = [3,4]

Ich möchte ein Array:

=> [f(1,3) ,f(1,4) , f(2,3) ,f(2,4)]
pierrotlefou
quelle
@ Lucasarruda, das ist nicht ganz das Gleiche wie das, was OP verlangt. Zip erstellt ein Array von [a[0], b[0]]und [a[1], b[1]]. Es würde nicht enthalten [a[0], b[1]]. a.zip(b) => [[1,3],[2,4]]
KNejad
Danke @KNejad, du bist richtig. Mein Kommentar wurde gelöscht.
Lucasarruda

Antworten:

147

Sie können verwenden product, um zuerst das kartesische Produkt der Arrays abzurufen und dann die Funktionsergebnisse zu erfassen.

a.product(b) => [[1, 3], [1, 4], [2, 3], [2, 4]]

So können Sie mapoder verwenden collect, um die Ergebnisse zu erhalten. Sie sind unterschiedliche Namen für dieselbe Methode.

a.product(b).collect { |x, y| f(x, y) }
Aaron Hinni
quelle
Produkt ist erst ab 1.9 eingebaut.
Pesto
7
Produkt ist in 1.8.7 - Ich benutze es, um genau das zu tun, was Pierr verlangt
Chris McCauley
1
@FloatingRock, das ist falsch, es ist eine Kombination, keine Permutation. Siehe ruby-doc.org/core-2.1.3/Array.html#method-i-product
Josh Diehl
1
@FloatingRock Nicht so. Das erste Element jedes Elements stammt immer aus der ersten Liste, das zweite Element aus der zweiten Liste usw. Es sind alles mögliche Kombinationen von Elementen, aber sie werden nie neu angeordnet, es sind also keine Permutationen.
Mark Reed
Und wenn Sie c = [5,6] und d = [7,8] haben, können Sie tun[a,b,c,d].reduce([[]]){|r,e| r=r.product(e)}.map{|x| x.flatten}
xxjjnn
11
a.map {|x| b.map {|y| f(x,y) } }.flatten

Hinweis: Ab Version 1.8.7 können Sie 1ein Argument zum Reduzieren hinzufügen , damit Sie bei der fRückgabe eines Arrays immer noch korrekte Ergebnisse erhalten .

Hier ist eine Abstraktion für eine beliebige Anzahl von Arrays:

def combine_arrays(*arrays)
  if arrays.empty?
    yield
  else
    first, *rest = arrays
    first.map do |x|
      combine_arrays(*rest) {|*args| yield x, *args }
    end.flatten
      #.flatten(1)
  end
end

combine_arrays([1,2,3],[3,4,5],[6,7,8]) do |x,y,z| x+y+z end
# => [10, 11, 12, 11, 12, 13, 12, 13, 14, 11, 12, 13, 12, 13, 14, 13, 14, 15, 12, 13, 14, 13, 14, 15, 14, 15, 16]
sepp2k
quelle
Dies wird funktionieren, obwohl ich nicht sicher bin, ob es der beste Weg ist (obwohl ich mir keinen besseren
vorstellen
Ich wünschte, ich könnte +2 für die Kombination einer beliebigen Anzahl von Arrays. Sehr cool!
Pierrotlefou
Ich kam auch damit heraus .. aber dann wusste ich, dass es einen einfacheren Weg geben sollte, es zu tun ... +1 dafür, aber der @ Aaron Hinni antwortet seinem Reiniger
Orlando
5

Facetten hat, Array#productdie Ihnen das Kreuzprodukt von Arrays geben. Es wird auch als Alias ** operatorfür den Fall mit zwei Arrays verwendet. Damit würde es so aussehen:

require 'facets/array'
a = [1,2]
b = [3,4]

(a.product b).collect {|x, y| f(x, y)}

Wenn Sie Ruby 1.9 verwenden, productist dies eine integrierte Array-Funktion.

Pesto
quelle
Warum sagen die Leute immer wieder, dass das Array # -Produkt ein 1.9ismus ist? Zumindest in 1.8.7.
Mark Reed