Gleichmäßig-Zufällige Array Verteilung

  • C#
  • .NET (FX) 4.0

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

    Gleichmäßig-Zufällige Array Verteilung

    Hey Community,

    Ich stehe vor einem Problem bei dem ich nicht weiß wie ich es am besten umsetzen soll :D
    Zuerst, was habe ich vor :
    Ich möchte ein T[] in mehrere kleine arrays unterteilen (mit random größen) und dann ein T[][] zurückgeben, also
    ein array welches die einzelnen kleineren arrays enthält.
    Wichtig ist das die Arrays schön ihre Reihenfolge behalten.
    Das konnte ich so umsetzen: (Dickes dankeschön an @~blaze~ )

    C#-Quellcode

    1. // Split an array into multiple multidemnsional arrays, with different, randomly choosen sizes
    2. public static T[][] RandomSplitBlock<T>(T[] input)
    3. {
    4. if (input == null)
    5. throw new ArgumentNullException("Input can't be null.");
    6. Random rnd = new Random(DateTime.Now.Millisecond);
    7. int index = 0;
    8. List<T[]> ArrayBlocks = new List<T[]>();
    9. while (index < input.Length)
    10. {
    11. int c = rnd.Next(1, input.Length - index);
    12. T[] newArr = new T[c];
    13. Array.Copy(input, index, newArr, 0, c);
    14. ArrayBlocks.Add(newArr);
    15. index += c;
    16. }
    17. return ArrayBlocks.ToArray();
    18. }


    Zum Problem.
    Der obrige algorithmus funktioniert recht gut, was ich jedoch möchte ist eine etwas gleichmäßigere, trotzdem random(!) verteilung
    der einzelnen arrayblöcke.

    Bei 30 Array Items als input kommen often solche Ergebnisse :

    z.B. unterteilt in 4 kleinere arrays, wobei:

    array[0] = enthält 23 items
    array[1] = enthält 2 items
    array[2] = enthält 4 items
    array[3] = enthält 1 items

    Ich möchte jedoch das versucht wird etwas gleichmäßigere Verteilungen zu erreichen, z.B. sowas:

    array[0] = enthält 7 items
    array[1] = enthält 6 items
    array[2] = enthält 8 items
    array[3] = enthält 9 items

    Also das nicht so enorme unterschiede wie z.B. 50 items und mal 2 items vorkommen, sondern halbwegs gleichmäßig.
    Das muss nicht immer exakt sein, aber es soll versucht werden möglich gleichgroße arrays zu er-splitten.
    Die Anzahl der zu erstellenden teil arrays soll nantürlich anch wie vor random gewählt werden, allerdings so, das
    das mit der aufteilung halbwegs passt, 26 arrays bei 30 array items als input wäre halt blöd :D
    Kann mir jemand helfen den Algorithmus so zu modifizieren das das oben beschrieben erreicht wird.
    Ich weiß nicht recht wie ich das machen soll, - hoffentlich kann mir hier jemand von euch helfen :)

    Lg
    Rikudo
    C# Developer
    Learning C++
    @petaod Jou.

    Rikudo schrieb:

    gleichmäßigere Verteilungen
    Mach Dir im 1. Schritt eine Liste mit entsprechenden Anzahlen und befülle dann entsprechend dieser Liste Deine Arrays:

    VB.NET-Quellcode

    1. Private rnd As New Random
    2. Private numbers As New List(Of Integer)
    3. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    4. For i As Integer = 0 To 9
    5. numbers.Add(rnd.Next(5, 9))
    6. Next
    7. End Sub
    Bilder
    • Numbers.png

      13,85 kB, 300×319, 130 mal angesehen
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Das wird aber nicht leicht, denn mir sind ja die Grenzen nicht bekannt:

    C#-Quellcode

    1. int c = rnd.Next(1, input.Length - index);


    Wenn ich eine Untergrenze von sagen wir ca 3 nehme, aber mein maximum ist nur 2, gibts probleme?
    Kann ich nicht automaticsh irgendwie einen Wert wählen der etwas abweicht?
    C# Developer
    Learning C++
    Du kannst z.B. zunächst anhand der Arraygröße ermitteln, wie viele kleinere Arrays du am Schluss ungefähr haben willst (dabei kannst du bereits eine zufällige Abweichung von einer dir sinnvoll erscheinenden Größe ansetzen). Dann berechnen, wie groß bei der ermittelten Anzahl ein Array sein müsste und bei jeder Iteration zu diesem Wert zufällig addieren und Subtrahieren (wobei du hier wiederum die Abweichung beliebig wählen kannst und vielleicht auch prozentual, also je größer die Teilarrays desto größer auch die mögliche Abweichung von dieser Länge).
    @Artentus :
    Oje, jetzt hast du mich verwirrt..
    Angenommen ich lege fest dass es sinnvoll ist jedem Teil-Array ca die Anzahl an Items zuzuweisen, die der Wurzel des Inputs entsprechen, mit einer Abweichung von +-2.
    Wie würde dann die Zuweisung von

    Quellcode

    1. int c
    aussehen?
    C# Developer
    Learning C++

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

    Genau das was @RodFromGermany geschrieben hat.

    C#-Quellcode

    1. int c = rnd.Next(untere Grenze, obere Grenze);

    Also hast du z.B. einen Array mit einer Länge von 40.
    Nun fehlt die Anzahl der Array die du als Output haben möchtest, nehmen wir 4. Dann berechnest du die durchschnittliche Größe des einzelnen Array mit 40 / 4 = 10. Als Abweichung der Arrays voneinander nehmen wir 10% der Länge des ursprünglichen Array also 40 / 10 = 4. Nun noch die 4 / 2 = 2 (5% über dem Mittelwert, 5% darunter) und dann hat man die untere Grenze mit Mittelwert - 2 und die obere mit Mittelwert + 2.
    ​Smartnotr - ein intelligentes Notizprogramm
    zum Thread

    @Mokki :
    Aber die Anzahl der Output array ist ja nicht imemr 4 sondern auch random.
    Ich habs so versucht :

    C#-Quellcode

    1. int c = rnd.Next((int)Math.Sqrt(input.Length), input.Length - index);


    Aber dann passiert genau das minvalue > maxvalue -> Crash :|
    C# Developer
    Learning C++

    petaod schrieb:

    Setze die Grenzen so: rnd.Next(Min(BerechneterUntererWert,ObererWert),ObererWert)


    ObererWert wäre ja dann :

    C#-Quellcode

    1. input.Length - index
    , oder?
    Aber was wäre UntererWert?

    Ich verstehs einfach nicht wie sich der zusammensetzen soll :(
    C# Developer
    Learning C++
    So:

    C#-Quellcode

    1. int c = rnd.Next(Input.Lenght / rnd.next(1,input.Lenght) - Input.Lenght / 10, Input.Lenght / rnd.next(1,input.Lenght) + Input.Lenght / 10);

    Falls eine Abweichung von max. 10% bestehen soll.
    ​Smartnotr - ein intelligentes Notizprogramm
    zum Thread

    Mokki schrieb:

    So:

    C#-Quellcode

    1. int c = rnd.Next(Input.Lenght / rnd.next(1,input.Lenght) - Input.Lenght / 10, Input.Lenght / rnd.next(1,input.Lenght) + Input.Lenght / 10);

    Falls eine Abweichung von max. 10% bestehen soll.


    Danke für deine Hilfe, aber das scheint nicht richtig zu funktionieren :D (Input größe des Arrays waren 29 items)

    C# Developer
    Learning C++
    Wenn du nichtmal angeben willst, wie viele Teilarrays rauskommen sollen, würde ich das so machen.
    Zur Veranschaulichung hat unser Array mal 30 Items.
    1. Eine Zufallszahl wählen, die etwa die Größe eines Teilarrays vorgibt. Ich würde vllt int size = rnd.Next(30 * 0.1, 30 * 0.4); vorschlagen.
    2. Dann wie gehabt fortsetzen, aber für die Arraygröße jetzt folgende Grenzen wählen : int c = rnd.Next(size - (size * 0.5), size + (size * 0.5));

    Dann wird bei größeren Arrays auch die Varianz größer.
    »There's no need to "teach" atheism. It's the natural result of education without indoctrination.« — Ricky Gervais

    ThePlexian schrieb:

    Wenn du nichtmal angeben willst, wie viele Teilarrays rauskommen sollen, würde ich das so machen.
    Zur Veranschaulichung hat unser Array mal 30 Items.
    1. Eine Zufallszahl wählen, die etwa die Größe eines Teilarrays vorgibt. Ich würde vllt int size = rnd.Next(30 * 0.1, 30 * 0.4); vorschlagen.
    2. Dann wie gehabt fortsetzen, aber für die Arraygröße jetzt folgende Grenzen wählen : int c = rnd.Next(size - (size * 0.5), size + (size * 0.5));

    Dann wird bei größeren Arrays auch die Varianz größer.


    Danke für deine Antowort, ThePlexian :)
    Allerdigns kommt da der gleiche Fehler wie bei Mokki's Vorschlag :

    C#-Quellcode

    1. public static T[][] RandomSplitBlock<T>(T[] Input)
    2. {
    3. if (Input == null)
    4. throw new ArgumentNullException("Input can't be null.");
    5. Random rnd = new Random(DateTime.Now.Millisecond);
    6. int index = 0;
    7. List<T[]> ArrayBlocks = new List<T[]>();
    8. while (index < Input.Length)
    9. {
    10. int size = rnd.Next((int)(Input.Length * 0.1), (int)(Input.Length * 0.4));
    11. int c = rnd.Next((int)(size - (size * 0.5)), (int)(size + (size * 0.5)));
    12. T[] newArr = new T[c];
    13. Array.Copy(Input, index, newArr, 0, c);
    14. ArrayBlocks.Add(newArr);
    15. index += c;
    16. }
    17. return ArrayBlocks.ToArray();
    18. }


    Probier das mal aus, da kommt der gleiche Fehler raus wie in dem Screenshot oben.
    Irgendwas scheint nicht zu stimmen mit den Grenzen..
    C# Developer
    Learning C++

    Rikudo schrieb:

    was wäre UntererWert
    Bei deinem genannten eigenen Vorschlag die Wurzel aus Input.Length.
    Ich wollte nur darauf hinweisen, dass du den Überlauf-Fehler mit Min abfangen kannst.

    Welchen Verteilalgorithmus du letztendlich wählst, bleibt dir und deinen Tests überlassen.
    Da führen viele Wege nach Rom.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --