Autor Beitrag
Herituus
Hält's aus hier
Beiträge: 2



BeitragVerfasst: Mi 21.07.10 09:57 
Hallo ihr,

ich habe folgendes Problem, ich möchte variable Stringketten erstellen.
Diese Kette soll beispielsweise alle Buchstaben von "aaa" bis "zzz" durchlaufen.
Sicher ist es möglich, das mit drei inneinander verschachtelte For Schleifen hinzubekommen, aber da das ganze variable gehalten werden soll, komme ich nicht darauf, wie ich quasi mit einer Schleife das abbilden könnte, wenn man alle Buchstaben von "a" bis "zzzzz" darstellen soll.


Hat jemand irgendeinen Ideenansatz?

Gruß Heri
danielf
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1012
Erhaltene Danke: 24

Windows XP
C#, Visual Studio
BeitragVerfasst: Mi 21.07.10 15:38 
Hallo,

für so einen Ansatz ist Rekursion immer verdächtig :) Habe demnächst auch so eine Methode implementiert.

Die Schleifen-Anzahl reduziert sich aber nicht, aber du musst "nur" eine Schleife implementieren. Innerhalb dieser Schleife rufst du für jede Möglichkeit wieder die gleiche Methode auf.

Gruß
norman2306
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 222
Erhaltene Danke: 16

Win XP, Win 7 64-Bit
C# 4.0 (VS2010)
BeitragVerfasst: Mi 21.07.10 17:09 
Das klingt nach einem Wortgenerator a lá BruteForce... da reichen drei Schleifen;)
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Mi 21.07.10 18:46 
Wenn ich das richtig verstanden habe, ist aaa-zzz nicht die Frage:
user profile iconHerituus hat folgendes geschrieben Zum zitierten Posting springen:
wie ich quasi mit einer Schleife das abbilden könnte, wenn man alle Buchstaben von "a" bis "zzzzz" darstellen soll.
Denk an ein 26-stelliges Zahlensystem, bei dem du von 0 an in Einerschritten vorangehst: ist die letzte Ziffer kleiner als Z, erhöhst du sie, sonst setzt du sie auf A und erhöhst die Ziffer davor etc...

Edit: Oder du nimmst natürlich deine Methode zum Erzeugen von n "A"s bis n "Z"s und rufst sie für n=1 bis 5 auf ;) .

_________________
>λ=
norman2306
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 222
Erhaltene Danke: 16

Win XP, Win 7 64-Bit
C# 4.0 (VS2010)
BeitragVerfasst: Do 22.07.10 08:51 
Ich wollt jetzt eigentlich mal Umschreiben, wie man des macht... aber ich bin zu faul. Ich habe sowas schonmal gemacht und Copy&Paste ist am einfachsten. Dafür musst du dich jetzt durch den Salat da durchackern:)

ausblenden volle Höhe C#-Quelltext
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:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
    public class WordEnumerator
    {
        private int wordLength;
        private char[] chars;
        private long actWord;
        private long maxWord;

        public int WordLength
        {
            get { return wordLength; }
        }

        public char[] Chars
        {
            get { return chars; }
        }

        public long ActWord
        {
            get { return actWord; }
            set { actWord = value; }
        }
        
        public long MaxWord
        {
            get { return maxWord; }
        }

        public WordEnumerator(char[] Chars, int WordLength)
        {
            this.actWord = 0;
            this.chars = Chars;
            this.wordLength = WordLength;

            this.maxWord = (long)Math.Pow(Chars.Length, wordLength);
        }

        public string getNextWord()
        {

            string result = getWord(actWord);

            if (actWord < MaxWord)
            {
                actWord++;
            }
            else
                actWord = 0;

            return result;
        }

        public string getWord(long ID)
        {
            StringBuilder sb = new StringBuilder();

            int[] ring = getRingExpr(ID);

            foreach (int i in ring)
            {
                sb.Append(Chars[i]);
            }

            return sb.ToString();
        }

        private int[] getRingExpr(long decimalNumber)
        {
            long nb = ;
            int[] res = new int[wordLength];

            int pos = 0;
            while (decimalNumber != 0)
            {
                res[pos] = (int)(decimalNumber % Chars.Length);
                nb = (int)(decimalNumber / Chars.Length);
                pos++;
            }

            return res;
        }
    }


Damit du auch noch was machen musst:
Du kannst jetzt den WordEnumerator in einer for-Schleife Aufrufen, in der du die Wortlänge hochzählst. In einer untergeordneten Schleife (while (we.ActWord < we.MaxWord)) kannst du dir jedes Wort dieser Länge generieren lassen.
Ist sicher nicht optimal, funzt aber super.

Ein Tip noch: so in etwa ab Wortlänge 4 bis 5 geht es sich nicht mehr, alle Worte zwischen zu Speichern, weil dann dein RAM relativ schnell zur neige geht... schließlich ist die Anzahl der Wörter in deinem Fall:
Summe(i=0; i<= Wortlänge){Anz(Chars)^i} was beim gesamten Alphabet relativ schnell gegen unendlich strebt. Daher ist die Verwendung der Enumeration sinnvoller und schneller.
danielf
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1012
Erhaltene Danke: 24

Windows XP
C#, Visual Studio
BeitragVerfasst: Do 22.07.10 13:48 
Sieht für mich verwirrend aus :)

Ich komme deshalb nochmal auf meinen Lösungsvorschlag mit der rekursiven Variante. Bei der man eine Liste an Elemente hat und daraus wiederum eine Liste von Elementen macht und die gleiche Funktion dann wieder aufruft bist genügend Stellen für die Permutation vorhanden sind.

Hier noch der Code:
ausblenden volle Höhe C#-Quelltext
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:
// Einstieg
// wobei elements eine Liste von elemente ist aus der man die Kette Bilden will
// length die Länge der späteren Kette (evtl. element.count ;))
// und duplicates ob ein Element innerhalb einer Kette doppel vorkommen kann
// d.h. Wenn duplikate erlaubt sind ist ein A A (bei length = 2) möglich
// ansonsten wäre die erste Lösung A B
private static List<List<T>> CreatePermutation<T>(List<T> elements, int length, bool duplicates)
{
    return CreatePermutation(new List<T>(), elements, duplicates, length);
}

// Die rekursive Funktion
        private static List<List<T>> CreatePermutation<T>(
            List<T> permutation,
            List<T> input,
            bool duplicates,
            int length)
        {
            List<List<T>> permutations = new List<List<T>>();

            for (int i = 0; i < input.Count && permutation.Count < length; i++)
            {
                if (duplicates || permutation.Contains(input[i]) == duplicates)
                {
                    List<T> newPermutation = new List<T>();
                    newPermutation.AddRange(permutation);
                    newPermutation.Add(input[i]);

                    permutations.AddRange(CreatePermutation<T>(newPermutation, input, duplicates, length));

                    if (newPermutation.Count == length)
                    {
                        permutations.Add(newPermutation);
                    }
                }
            }

            return permutations;
        }


Nun hat man eine "genersiche" Permutationsfunktion. Für Anregungen bin ich dankbar :)

Hier noch ein Anwendungsbeispiel:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
            List<char> alphabet = new List<char>();

            for (int i = 0; i < 3; i++)
            {
                alphabet.Add(char.ConvertFromUtf32(65 + i).ToCharArray()[0]);
            }

            List<List<char>> t = CreatePermutation(alphabet, alphabet.Count, true);


t beinhaltet nun alle Möglichkeiten die mit den ersten 3 Buchstaben des Alphabets (27) Möglich sind). Da Duplikate erlaubt sind erzeugt er auch AAA, BBB, CCC .. bzw ABA usw.

Ruft man das gleiche ohne Duplikate auf gibt es 6 Lösungen:
ABC
ACB
BAC
BCA
CAB
CBA

Gruß Daniel
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Do 22.07.10 21:33 
Sieht hübsch aus :) .

Aber vielleicht sollte man der Einfachheit halber doch lieber die Aufgabenstellung direkt in Angriff nehmen:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
static IEnumerable<string> Loop(int length)
{
    if (length == 0)
        yield return "";
    else
        foreach (string s in Loop(length - 1))
            for (char c = 'A'; c <= 'Z'; c++)
                yield return s + c;
}

for (int i = 1; i <= 3; i++)
    foreach (string s in Loop(i))
        Console.WriteLine(s);

_________________
>λ=
norman2306
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 222
Erhaltene Danke: 16

Win XP, Win 7 64-Bit
C# 4.0 (VS2010)
BeitragVerfasst: Do 22.07.10 22:08 
Naja, meine Variante stammt noch aus meiner Sturm und Drang Zeit mit FW2.0 und kann eben durch das Char-Array Wörter aus beliebigen Zeichen bilden (das geht bei Khas Code natürlich auch). Mit einer kleinen Erweiterung kann man auch noch für bestimmte Anwendung typische Strings definieren (":-)") und anhängen, die für bestimmte Sachen gern genommen werden, um sie sicherer zu machen. Am elegantesten ist natürlich Khas Variante.
Herituus Threadstarter
Hält's aus hier
Beiträge: 2



BeitragVerfasst: Mo 02.08.10 09:35 
Abschließend möchte ich allen danken, die sich mit meinem Problem auseinander gesetzt haben.

Vielen Dank ihr seid wirklich prima!