Thread Zahlenkombinationen suchen
(16 answers)
Opened by hugenyn at 2010-10-22 00:55
So wie du es macht hast du mehrere probleme, später und das hat nichts mit der Unhandlichkeit des Codes zu tun. Du weist nachher nur noch aus der Position der Summe im Array welche Kartenkombination die Summe ergeben hat. Das ist weder skalierbar noch übersichtlich. Darum habe ich einen Hash verwendet der als Schlüssel die Summe hat und als wert ein anonymes Array mit den Kartennummern.
Man kann das Problem ganz klassisch rekursiv lösen: Code (perl): (dl
)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 sub combinations { # übernehme die Karten my @cards=@_; # wenn keine Karten an die Funktion übergeben wurden liefere eine leere Liste zurück return [] unless (@cards); wenn nur eine Karte in der Liste ist dann liefere nur die Liste zurück return \@cards if(@cards==1); # erzeuge die liste mit den restlichen Kombinationen: my @ret; # solange noch karten vorhanden sind: while(@cards) { # nimm die erste Karte heraus my $card=shift(@cards); # füge diese Karte des RückgabeArrays hinzu push(@ret,[$card]); # rufe die Funktion selber wider auf und gehe das Ergebnis durch (ist ein array) # das ist rekursive teil, das die Funktion sich immer wieder selber aufruft, # die übergebene liste ist aber immer um ein Element kürzer # darum kommt die Rekursion irgendwann zu einem Ende (siehe oben) for my $r (combinations(@cards)) { # $r enthält eine Arrayrefenz! # füge die herausgenommene Karte wieder ein # und füge die das dem RückgabeArray hinzu push(@ret,[@$r,$card]) if(@$r); } } # gib das RückgabeArray zurück return @ret; } rekursive Funktionen sind zu Anfang schwer zu verstehen, aber das gibt sich mit der Zeit. Am einfachsten ist es du spielst das auf dem Papier durch: Code: (dl
)
1 aufruf: combinations(1 2 3 4) Wie du siehst erzeugt die Rekursion alle nötigen Kombination. (Mein erster Code ist komplexer, weil ich nicht genügend nachgedacht habe. :-) ) Der Code lässt sich auch sehr kompakt schreiben: Code (perl): (dl
)
1 2 3 4 5 6 7 8 9 10 11 sub combinations { return [] unless (@_); my @ret; while(@_) { my $card=shift(@_); push(@ret,[@$_,$card]) for(combinations(@_)) } return @ret; } Und der Code kommt mit beliebig vielen Karten klar. In dem und auch bei deinem Code kann es ein paar unnötige Kombinationen geben, wenn mehrere gleiche Karten auf der Hand sind. Um das Problem zu lösen kann man wunderbar eine Besonderheit von Hashes nutzen. Die Schlüssel in einem Hash kommen niemals doppelt vor. Die Lösung ist also: sortiere das Array, füge die Werte daraus es zusammen und nutze den so erzeugten String als Schlüssel. Wenn der Schlüssel schon im Hash vorkommt, dann verwerfe das Array. An einem Beispiel: Code (perl): (dl
)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 # gegeben sei ein Array mit Arrays: my @array=( [1], [1 3 4], [1 2 3 4], [1 2 3 4], [2 3 1 4], [4 3 1], ); # definiere einen Hash, # der die als Indikator für die doppelten Werte dienen soll: my %unique; # das Array für die Werte # ohne die doppelten my @unique_array; # gehe das Array @array durch: for my $array_ref (@array) { # $array_ref ist eine referenz auf ein Array, # das muss etwas anders behandelt werden als ein normales Array. # das Array sortieren und gleichzeitig eine Kopie anlegen: my @copy=sort(@$array_ref); # wenn man ein Array in Doppelte Anführungszeichen setzt, # dann fügt Perl dort die elemnte der liste ein. # man kann also schreiben my $key="@copy"; # und bekommt einen string den man als Schlüssel verwenden kann. # nun wird geprüft ob der String als Schlüssel noch nicht im Hash ist: if(!$unique{$key}) { # setze den Schlüssel, # damit ein Array mit den selben Werten nicht nochmal eingefügt wird. $unique{$key}=1; #füge das Array @unique_array hinzu: push(@unique_array,\@copy); # hier ist es wichtig eine Refenz hinzu zu fügen! } } # in @unique_array sind nun Arrayrefenzen mit einzigartigen Wertkombinationen Es gibt verschiedenen Möglichkeiten die Funktionalität zu schreiben, lass dich davon nicht irritieren. eine davon: Code (perl): (dl
)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 # gegeben sei ein Array mit Arrays: my @array=( [1], [1 3 4], [1 2 3 4], [1 2 3 4], [2 3 1 4], [4 3 1], ); my %unique; my @unique_array=grep{$unique{"".join " ", sort @$_}++}@array; # in @unique_array sind nun Arrayrefenzen mit einzigartigen Wertkombinationen Last edited: 2010-10-27 02:57:32 +0200 (CEST) |