Problem bei For Schleife (Random String Generator)

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 24 Antworten in diesem Thema. Der letzte Beitrag () ist von seh.

    Problem bei For Schleife (Random String Generator)

    Hallo,

    derzeit versuche ich in VB.net einen Random String zu generieren,
    welcher so aussehen soll: RANDOM LETTER + 8 RANDOM NUMBERS.
    Dieses soll mehrfach generiert werden und in einer Listbox eingetragen werden.

    Das sieht bis jetzt so aus:

    VB.NET-Quellcode

    1. For i As Integer = 0 To 4
    2. ' generate random letter
    3. Dim s As String = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    4. Dim r As New Random
    5. Dim sb As New System.Text.StringBuilder
    6. For i2 As Integer = 1 To 1
    7. Dim idx As Integer = r.Next(0, 25)
    8. sb.Append(s.Substring(idx, 1))
    9. Next
    10. ' generate 8 random numbers
    11. Dim rand As New Random()
    12. Dim number = rand.Next(10000000, 99999999)
    13. panel.ListBox1.Items.Add(sb.ToString() + number.ToString)
    14. Next


    Das funktioniert auch alles ganz gut nur habe ich da ein Problem...
    Es wird die ganze Zeit der gleiche String in der Listbox eingetragen und
    kein neuer erstellt...



    Wird zwar wahrscheinlich nen kleiner Fehler sein aber ich finde ihn einfach nicht ^^

    Schon mal danke für jede Hilfe.

    MfG Tobi
    :D
    Ursache ist, das ist Zufallsroutine schneller aufgerufen wird, als Zufallswerte erzeugt werden können.
    quatsch.
    Man darf nur nicht für jede Randomzahl ein neues Random-Objekt erstellen.
    Man erstelle ein einziges mal ein Random-Objekt - das liefert dann alle Random-Zahlen. Und zwar schneller als der Blitz.
    Tobi, mach mal so:

    VB.NET-Quellcode

    1. Dim rnd As New Random()
    2. For i As Integer = 0 To 4
    3. ListBox1.Items.Add(String.Format("{0}{1}", Convert.ToChar(rnd.Next(65, 90)), rnd.Next(10000000, 99999999)))
    4. Next

    oder halt in c#:

    C#-Quellcode

    1. Random rnd = new Random();
    2. for (int i = 0; i < 5; i++)
    3. listBox1.Items.Add(String.Format("{0}{1}", Convert.ToChar(rnd.Next(65, 90)), rnd.Next(10000000, 99999999)));

    Selter98 schrieb:

    Dieses Problem hatte ich auch. Ich habe mich mit

    VB.NET-Quellcode

    1. System.Threading.Thread.Sleep(30)

    beholfen.

    Ursache ist, das ist Zufallsroutine schneller aufgerufen wird, als Zufallswerte erzeugt werden können.


    Auch wenn es funktionieren würde, fände ich diese Methode nicht so gut da z.B. Bei 250 Generates schon eine höhere Wartezeit kommt.
    :D
    Hi
    ein wichtiger Hinweis: Die obere Grenze ist exklusiv, d.h. bei simpleSofts Vorschlag käme die 99999999 nie vor, da die Zufallswerte im Bereich von Minimum bis (Maximum - 1) liegen.

    Sleep ist nicht nötig. Einfach nur ein Random-Objekt instanziieren und das dann verwenden. Der Konstruktor (d.h. New Random()) erzeugt einen Zufallsgenerator auf Basis einer zeitabhängigen Größe. Der Zeitgeber ist aber nicht so exakt, weshalb die gleiche Zeit mehrmals verwendet wird, da die CPU weit schneller ist, als der Zeitgeber präzise. Und das führt dann halt zu gleichen Werten. Next basiert stets auf den vorangegangenen Werten, weshalb es dann kein Problem ist, das mehrmals in kurzen Zeitabständen abzurufen: Nur der erste Wert hängt von der Zeit ab, die als Seed verwendet wird. Der Seed ist der Wert, von dem aus die Zufallszahlen berechnet werden (d.h. wenn man ihn nicht explizit angibt, ist das also Environment.TickCount).

    Viele Grüße
    ~blaze~
    @simpleSoft
    Hmm, auf meinem Handy habe ich dir eben eigentlich geschrieben das ich es nachher mal ausprobieren werde,scheint aber nicht angekommen zu sein... Trotzdem danke :)

    @~blaze~
    Ok danke für die Information :)

    MfG

    ~blaze~: Vollzitate entfernt
    :D

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „~blaze~“ ()

    ~blaze~ schrieb:

    Hi
    ein wichtiger Hinweis: Die obere Grenze ist exklusiv, d.h. bei simpleSofts Vorschlag käme die 99999999 nie vor, da die Zufallswerte im Bereich von Minimum bis (Maximum - 1) liegen.


    Wenn denn, dann bitte "Tobis Vorschlag", ich habe nur seine Zahlen übernommen ;)
    Pardon. ;)

    Statt der Convert-Klasse empfehle ich übrigens für die Konvertierung zwischen den primitiven Datentypen (Byte, SByte, UShort, Short, UInteger, Integer, ULong, Long, Char, Single, Double, Boolean, hab' ich was vergessen? Deicmal und String sind keine) CByte, Asc, Chr, usw. Nur bei Boolean natürlich nicht, da würde ich auf If zurückgreifen.

    Viele Grüße
    ~blaze~

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „~blaze~“ ()

    @~blaze~ Du empfiehlst Asc und Chr, obwohl die im VisualBasic-Namespace beheimatet sind?
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Ja. In VB.Net wurde nach meiner Einschätzung Funktionalität so bereitgestellt, dass sie einen Kompromiss zwischen dem alten VB6 und dem neuen VB.Net bildet. Daher schätze ich, dass die Entscheidung, Asc und Chr anstatt hinzuzufügen, statt CInt, usw. dafür zu verwenden, daher ruht, dass man das in VB.Net so vorgesehen hat.
    Wenn man mich nach meiner Meinung fragt, würde ich sagen, dass man das machen soll, was man für richtig hält, wenn man weiß, dass es so passt, wie es ist (die letzte Bedingung ist die wichtige).

    Und insgesamt würdre ich jedem empfehlen, für die Verwendung von .Net C# zu lernen und sich VB.Net nur mal anzuschauen. C# ist einfach so weit schöner zu programmieren. Und nur weil C# auf Klammern basiert, anstatt auf Wörtern, macht's das nicht schwieriger.

    Viele Grüße
    ~blaze~
    Neuerdings gehe ich übrigens dazu über, den Namespace-GeneralImport Microsoft.VisualBasic zu ersetzen durch den General-Namespace-ShortCut VB6=Microsoft.VisualBasic.
    Dann kann man Asc auch benutzen, ohne sich den lokalen Namespace mit dem vb6-Müll vollzumüllen.
    Es heisst dann halt VB6.Asc(<expression>)
    Hab ich gestern bei mir so im Projekt implementiert:

    C#-Quellcode

    1. public static string NextString(this Random random, int charCount)
    2. {
    3. var alphabet = "abcdefghijklmnopqrstuvwxyz";
    4. var str = new StringBuilder();
    5. for(int i = 0; i < charCount; i++)
    6. {
    7. str.Append(alphabet[random.Next(0, alphabet.Length - 1)]);
    8. }
    9. return str.ToString();
    10. }


    Edit: Random einmal zuvor initialisiert mit Environment.TickCount.

    Grüße
    Random musst du nicht mit Environment.TickCount initialisieren, das macht es ohne Angabe von selbst. Außerdem muss es alphabet[random.Next(0, alphabet.Length)] lauten (siehe oben).
    Es wäre zudem wichtig, abzufragen, ob charCount gültig (nicht-negativ) ist. Noch besser wäre es, das Alphabet einfach direkt als Parameter zu fordern und eine Überladung anzubieten, die mit a-z arbeitet.

    Viele Grüße
    ~blaze~

    ~blaze~ schrieb:

    Außerdem muss es alphabet[random.Next(0, alphabet.Length)] lauten (siehe oben).


    Du hast Recht, ich habe mir nochmal die Dokumentation durchgelesen, ist aber echt verwirrend. maxValue wird dabei niemals erreicht, es ist nur die Obergrenze, alles darunter was minValue oder größer ist kann vorkommen.

    Wird alles übernommen. Danke :thumbup:

    Edit:

    C#-Quellcode

    1. ​public static string NextString(this Random random, int charCount, string characterSet = "abcdefghijklmnopqrstuvwxyz")
    2. {
    3. if (charCount <= 0)
    4. throw new ArgumentException("charCount needs to be greater than zero.");
    5. var str = new StringBuilder();
    6. for (int i = 0; i < charCount; i++)
    7. {
    8. str.Append(characterSet[random.Next(0, characterSet.Length)]);
    9. }
    10. return str.ToString();
    11. }


    Hab das characterSet jetzt als Parameter mit einem Standardcharacterset, und wer will kann ein Custom Characterset benutzen.
    charCount wird jetzt auf Negativität geprüft.
    Zufallsbereich wird jetzt richtig genutzt.

    seh schrieb:

    Wird alles übernommen. Danke :thumbup:

    Eigentlich hat ja Dein Programm nichts mit dem eigentlichen Thema zu tun, aber ich habe mir mal erlaubt, Deinen Code auf eine Zeile einzudampfen und auch auf das Random verzichtet.
    Weiterer Vorteil, es werden unique Strings erzeugt, naja, so gut wie ^^ ..

    C#-Quellcode

    1. private string NextString(int charCount)
    2. {
    3. return String.Concat(Guid.NewGuid().ToString("N").Select(c => (char)(c + 17)).Take(charCount)).ToLower();
    4. }

    ~blaze~ schrieb:

    Der leere String ist auch gültig

    Das stimmt zwar, aber ergibt eigentlich keinen Sinn. Naja habs trotzdem mal gemacht.

    ~blaze~ schrieb:

    Aus Effizienzgründen würde ich die Abfrage einfach über der Erzeugung des StringBuilders einbauen.

    Das verstehe ich nicht, welche Abfrage meinst du? Die charCount Abfrage ist doch über der Erzeugung des StringBuilder Objekts ?(

    simpelSoft schrieb:

    seh schrieb:

    Wird alles übernommen. Danke :thumbup:
    Eigentlich hat ja Dein Programm nichts mit dem eigentlichen Thema zu tun, aber ich habe mir mal erlaubt, Deinen Code auf eine Zeile einzudampfen und auch auf das Random verzichtet.Weiterer Vorteil, es werden unique Strings erzeugt, naja, so gut wie ..

    C#-Quellcode

    1. private string NextString(int charCount){return String.Concat(Guid.NewGuid().ToString("N").Select(c => (char)(c + 17)).Take(charCount)).ToLower();}
    Coole Lösung! Werd' ich mir merken. Danke Dir :thumbup: