2013-11-03 10 views
5

Firs aller entschuldigen Sie mich für mein schlechtes Englisch. Ich versuche, Kombinationen von Symbolen aus str: TStringList (Xn, Yn) zu generieren, wobei X die Position des Zeichens im neuen Wort und Y die Variable für die Position ist.
Zum Beispiel läßt meinen String
Combinaions von X, Y-String in massivem

str[0]: '013456789'   
str[1]: 'abcdef' 
str[2]: '5421' 


In diesem Fall müssen sagen, dass ich 216 Worte expact werde (Länge (str [0]) * Länge (str [1]) * Länge (str [ 2])) Das Ergebnis wird sein, wie:

str[0][1]+ str[1][1]+ str[2][1] -> 0a5 
str[0][1]+ str[1][1]+ str[2][2] -> 0a4 
str[0][1]+ str[1][1]+ str[2][3] -> 0a2 
str[0][1]+ str[1][1]+ str[2][4] -> 0a1 

str[0][1]+ str[1][2]+ str[2][1] -> 0b5 
str[0][1]+ str[1][2]+ str[2][2] -> 0b4 
str[0][1]+ str[1][2]+ str[2][3] -> 0b2 
str[0][1]+ str[1][2]+ str[2][4] -> 0b1 

str[0][1]+ str[1][3]+ str[2][1] -> 0c5 
str[0][1]+ str[1][3]+ str[2][2] -> 0c4 
str[0][1]+ str[1][3]+ str[2][3] -> 0c2 
str[0][1]+ str[1][3]+ str[2][4] -> 0c1 

und so weiter, bis

str[0][10]+ str[1][6]+ str[2][3] -> 9f2 
str[0][10]+ str[1][6]+ str[2][4] -> 9f1 

Jetzt bin ich verwirrt, wie man die FOR-Schleifen macht, um cicles für jedes mögliche Wort zu machen.

Mit freundlichen Grüßen Martin

+1

wissen Sie das Wort im Voraus in Ihrer 'str' Stringliste zählt (bei der Kompilierung)? – TLama

+0

Nein, die Anzahl der Strings und die Länge der einzelnen Strings werden zur Laufzeit geladen. – user2949632

+3

Klingt nach Hausaufgaben? :) –

Antwort

3

Dies kann mit Rekursion durchgeführt werden.

procedure Recurse(startIx,stopIx: Integer; prefix: String; const aList: TStringList); 
var 
    ch : Char; 
begin 
    if (startIx > stopIx) then begin 
    WriteLn(prefix); 
    end 
    else 
    begin 
    for ch in aList[startIx] do begin 
     Recurse(startIx+1,stopIx,prefix + ch,aList); 
    end; 
    end; 
end; 

Recurse(0,str.Count-1,'',str); 

Rekursion wie Magie zunächst erscheinen mag, aber es ist ein sehr effektiver Weg, um diese Art der Kombinatorik zu lösen.

Die Lösung für dieses Problem ist ein Cartesian product.

Sollten Sie eine ältere Version von Delphi, ITERATE das Zeichen wie folgt aus:

procedure Recurse(startIx,stopIx: Integer; prefix: String; const aList: TStringList); 
var 
    i : Integer; 
begin 
    if (startIx > stopIx) then begin 
    WriteLn(prefix); 
    end 
    else 
    begin 
    for i := 1 to Length(aList[startIx]) do begin 
     Recurse(startIx+1,stopIx,prefix + aList[startIx][i],aList); 
    end; 
    end; 
end; 
+0

hm Ich weiß nicht warum, aber ich kann nicht "für ch in aList [startIx]" becose von Fehler "Operator nicht auf diesen Operand Typ anwendbar". Vielleicht alte Version von Delphi? (derzeit mit 7) – user2949632

+0

@ user2949632, habe ich eine Lösung hinzugefügt, die mit Delphi-7 funktioniert. –

+0

Ja funktioniert gut, danke. Jetzt werde ich die beiden Methoden mit 1m Kombinationen testen, um den Unterschied in der Geschwindigkeit der "Generation" zu sehen. – user2949632

1

Sie müssen Nest 3 für Schleifen zusammen. Ich gehe davon aus, dass Index von str Array beginnt bei Null, sondern Indizes der zweiten Dimension Start von 1:

var i,j,k:integer; 

begin 
    s = ''; 
    for i:=1 to length(str[0]) do 
     for j:=1 to length(str[1]) do 
      for k:=1 to length(str[2]) do 
      begin 
       combination := str[0][i]+str[1][j]+str[2][k]; 
       s := s + combination + chr(13) + chr(10); 
      end; 
    { you have all combinations in string s } 
end; 

Wenn Sie variable Anzahl von Zeichen Länge benötigen könnten Sie es wie folgt implementieren:

procedure TForm1.FormCreate(Sender: TObject); 
var str: array [0..10] of string; 
    lengths : array [0..10] of integer; 
    combination : string; 
    index: array [0..10] of integer; 
    n, i,j : integer; 
    maxn : integer; 
begin 
    n := 3; { actual number of charaters in output word } 
    str[0]:= '013456789'; 
    str[1]:= 'abcdef'; 
    str[2]:= '5421'; 


    { lengths will be used often later so they will be determined one time } 
    for i:=0 to n-1 do lengths[i] := length(str[i]); 
    maxn := 1; { maxn will be used to determine how meny iterations to make } 
    for i:=0 to n-1 do maxn := maxn * lengths[i]; 
    { start at index 1 (first character) with each character position } 
    for i:=0 to n-1 do index[i]:=1; 


    memo1.Lines.Add(inttostr(maxn)); 

    { iterate all possibilities } 
    for i:=1 to maxn do 
    begin 
     { start creating a combination } 
     combination:=''; 
     for j:=0 to n-1 do 
     begin 
     combination := combination + str[j][index[j]]; 
     end; 
     memo1.Lines.Add(combination); 
     { increment indexes, from last to the first } 
     for j:=n-1 downto 0 do 
     begin 
     index[j] := index[j]+1; 
     { if index is in bounds of character posibilities stop incremented indexes, 
      otherwise reset the index and increment next one } 
     if index[j]<=lengths[j] then 
     begin 
      break; { stop incrementing indexes } 
     end else begin 
      index[j] := 1; { reset the index } 
      { the loop will continue incrementing previous index } 
     end; 
     end; 
    end; 
end; 

statt Verwenden Sie feste Variablen für den Zeichenindex wie i,j,k Sie können sie in einem Array index speichern. Das Inkrementieren von Indizes funktioniert wie beim manuellen Hinzufügen von zwei Zahlen auf einem Papier. Versuchen Sie hinzuzufügen

999 
+ 1 
---- 

, um die Idee zu bekommen.

+2

Was ist, wenn die Anzahl der Strings n ist? –

+0

Mein letztes Skript ist genau wie Ihres. Aber jetzt bin ich auf Schleifenzählungen beschränkt. Also meine Fragen ist, wie man FOR-Schleifen in der Laufzeit nach 'str.Count-1' macht. Zum Beispiel mit verschiedenen Bedingungen werde ich str.count 100 (100 Zeichen für jedes generierte Wort) haben. Und Entschuldigung für meine Explonation in meinem ersten Beitrag. – user2949632

+0

Sie können Indizes in einem Array anstelle von festen Variablen wie i, j, k speichern Sie können dann das Problem mit maximal zwei verschachtelte für Zyklen lösen – nio