2010-12-13 3 views

Antwort

2

Eine Alternative ist das Modul Set::CrossProduct, die gewöhnliche, unblessed Array Referenzen ergeben wird:

use Set::CrossProduct; 
my $iter = Set::CrossProduct->new([ \@foo, \@bar ]); 

while (my $tuple = $iter->get){ 
    ... 
} 

Oder alle Tupel auf einmal erhalten:

my @tuples = $iter->combinations; 
1

Es die Arrays von cartesian zurück segnet, so dass, wenn einige Code wie der folgende wird

laufen
$b = $cartesian $a1, $a2; 
$c = $cartesian $b, $a3; 

... es kann erkennen, dass $b das Ergebnis eines vorherigen Aufrufs des Moduls ist.

Das Ausführen einer kartesischen Produktoperation ist etwas trivial. Wenn die von diesem Modul zurückgegebenen Daten nicht Ihren Anforderungen entsprechen, sollten Sie die Operation von Grund auf selbst schreiben.

Wie auch immer, die Inspektion des Modul-Quellcodes zeigt, dass es nicht zu groß ist.

+2

'Set :: CrossProduct' ist eine gute Alternative.Siehe http://search.cpan.org/perldoc/Set::CrossProduct –

+1

Als Gegengewicht zu Sinans guter Alternative, stattdessen eine schlechte Alternative: my @cartesian = do {local $ "= ','; <{@ foo } {@ bar}>}; Das geht schnell kaputt, wenn Ihre Arrays globale Metazeichen enthalten, aber ist es nicht * Spaß *? – Hugmeir

4

Ich habe eine cartesian Funktion List::Gen kürzlich:

  • cartesian CODE LIST_of_ARRAYREF

    cartesian berechnet das kartesische Produkt aus einer beliebigen Anzahl von Array-Refs, von denen jedes eine beliebige Größe haben kann.

    Ein Generator liefert
    use List::Gen 'cartesian'; 
    my $product = cartesian {$_[0] . $_[1]} [qw/a b/], [1, 2]; 
    print "@$product"; # 'a1 a2 b1 b2' 
    

"Generator" zurückgegeben wird, ist ein fauler gebunden Array, die Werte erzeugen, wenn für sie gefragt. Darüber hinaus gibt es iterative und andere Zugriffsmethoden:

my $pairs = cartesian {@_} [qw/$ @ %/], ['a'..'z'], [1 .. 3]; 

while (my @tuple = $pairs->next) { # $pairs->reset; #$pairs->index = 5; ... 
    print @tuple, ', '; 
} 
# $a1, $a2, $a3, $b1, $b2, $b3, $c1, $c2, $c3, $d1, $d2, $d3, $e1 ... 

Ich weiß nicht, wie groß die Sätze mit denen Sie arbeiten können, aber der Vorteil auf den oben beschriebenen Ansatz besteht darin, dass der Speicherbedarf für den Generator bleiben O(1)

my $digits = cartesian {join '' => @_} ([0..9]) x 10; 

say for @$digits[10**9 - 3 .. 10**9 + 3]; 

# 0999999998 
# 0999999999 
# 1000000000 
# 1000000001 
# 1000000002 
# 1000000003 

berechnet nur 6 Elemente des Satzes und speichert nichts. Wie Sie aus den Beispielen sehen können, ist der Rückgabewert von cartesian selbst ein Generatorobjekt, aber die nachfolgenden Rückgabewerte dieses Objekts sind, was auch immer die cartesian zurückgegebene Coderef zurückgibt. Also, wenn Sie Array Referenzen wollen, es ist so einfach wie: cartesian {\@_} ...


Auch, was zusätzliche Arbeit haben Sie zu tun haben, mit dem gesegneten Verweis umgehen? Ein gesegnetes Array ist immer noch ein Array in jeder Hinsicht außer dem, was ref zurückgibt. Wenn Sie eine Schalterlogik basierend auf dem Referenztyp schreiben, sollten Sie Scalar::Utilreftype verwenden.