Ausreichend Zufallszahlen nach vorgegebenem Muster funktioniert nicht immer

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Atalanttore
User
Beiträge: 407
Registriert: Freitag 6. August 2010, 17:03

Hallo

Ich habe eine einfache Funktion zum Erstellen von Zufallszahlen nach einem vorgegebenen Muster geschrieben.

Code: Alles auswählen

import random


random_indexes = []


def create_random_indexes(start, end, elements):

    while len(random_indexes) < elements:
        random_number = random.randint(start, end + elements)

        if random_number not in random_indexes and \
                                random_number - 1 not in random_indexes and \
                                random_number + 1 not in random_indexes:

            random_indexes.append(random_number)


create_random_indexes(0, 1500, 1141) # funktioniert nicht immer

print(sorted(random_indexes))
Manchmal erzeugt die Funktion eine Liste mit genügend passenden Zufallszahlen und manchmal nicht.

Hängt das erfolgreiche Ausführen dieser Funktion davon ab, ob die erzeugten Zufallszahlen gut zum vorgegebenen Muster passen oder liegt es an etwas anderem?

Gruß
Atalanttore
nezzcarth
User
Beiträge: 1632
Registriert: Samstag 16. April 2011, 12:47

Da du auf eine globale Datenstruktur ('random_indexes') zugreifst, hängt die "Rückgabe" insbesondere von vorherigen Aufrufen ab. Das sollte so nicht sein; 'random_index' gehört in die Funktion. Ich würde zumindest bei den gezeigten Parametern auch fast schon nicht mehr von Zufallszahlen sprechen, da du den Ergebnisraum extrem eingeschränkt hast. Das ist auch der Grund, warum es einige Konfigurationen gibt, die sofort zu Resultaten führen, andere hingegen lange brauchen oder gar nicht terminieren.
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

Ich verstehe nicht ganz, warum die Zufallszahlen zwischen start und end+elements ausgewählt werden. Wenn ich ein Ende vorgebe, will ich ja keine Zahlen die größer (oder gleich) sind. Um sicher zu gehen, dass die Funktion terminiert, muß eben der Bereich mindestens dreimal so groß sein, wie die Anzahl der Elemente.
Wie nezzcarth schon geschrieben hat, sollte eine Funktion keine globalen Variablen verwenden und ihr Ergebnis als Rückgabewert zurückliefern.
Folgende Funktion bricht mit einem Fehler ab, falls nicht genug „Zufallszahlen” gezogen werden können:

Code: Alles auswählen

def create_random_indexes(start, end, elements):
    result = []
    numbers = set(range(start, end))
    for _ in range(elements):
        number = random.choice(list(numbers))
        numbers -= {number - 1, number, number + 1}
        result.append(number)
    return result
Atalanttore
User
Beiträge: 407
Registriert: Freitag 6. August 2010, 17:03

Die Ergebnisliste soll die gleiche Anzahl an Elementen haben wie die Liste `end`, aber ohne die Zufallszahlen der Liste `elements`. Deshalb habe ich den Bereich der Zufallszahlen mit `end + elements` erweitert.

Bis auf die markierte Anweisung ist mir der folgende Code klar.

Code: Alles auswählen

def create_random_indexes(start, end, elements):
    result = []
    numbers = set(range(start, end))
    for _ in range(elements):
        number = random.choice(list(numbers))
        numbers -= {number - 1, number, number + 1} # ?
        result.append(number)
    return result
Die Funktion `set()` zum Erzeugen einer Menge ist anscheinend für die Anweisung `numbers -= {number - 1, number, number + 1}` wichtig. Ohne `set()` bekommt man den Fehler `TypeError: unsupported operand type(s) for -=: 'range' and 'set'`.

Die Anweisung `numbers -= {number - 1, number, number + 1}` beschränkt anscheinend die Zufallszahlen auf das vorgegebene Muster, aber was die Anweisung genau bedeutet ist mir nicht so recht klar.

Gruß
Atalanttore
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

@Atalanttore: - ist die Mengenoperation ›ohne‹. `end` ist keine Liste, was soll daher »Die Ergebnisliste soll die gleiche Anzahl an Elementen haben wie die Liste `end`,« heißen? Die Ergebnisliste soll doch die Anzahl `elements` Elemente haben.
Atalanttore
User
Beiträge: 407
Registriert: Freitag 6. August 2010, 17:03

@Sirius3: Was bewirken dann die geschweiften Klammern? Bei einem `set()` kommen doch eigentlich eckige Klammern zum Einsatz.

Ich meinte natürlich die Liste `numbers` anstatt `end`. :roll:

Gruß
Atalanttore
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

Bei Sets kommen eigentlich geschweifte Klammern zum Einsatz. Dieses undokumentierte Vergrößern des Ranges macht für mich aber immer noch keinen Sinn. Wenn die Eingangsliste tatsächlich gleich viele Elemente wie die Ergebnisliste haben soll, dann kann da nicht viel Zufall drin stecken.
nezzcarth
User
Beiträge: 1632
Registriert: Samstag 16. April 2011, 12:47

Atalanttore hat geschrieben: Sonntag 19. August 2018, 21:05 Bei einem `set()` kommen doch eigentlich eckige Klammern zum Einsatz.
Atalanttore
Ergänzend zu dem, was Sirius3 schrieb: Es gibt für viele eingebaute Datentypen in Python zwei Arten, diese zu definieren: Einmal über Literale und einmal über Konstruktoren. Die literale Schreibweise für Listen ist '[1,2,3]', für Mengen '{1, 2, 3}' und für Tupel '(1, 2, 3)'. Die Konstruktoren nehmen als Parameter ein Iterable und geben dann einen entsprechend befülltes Objekt des jeweiligen Typs zurück. Wenn du also 'set([1, 2, 3])' schreibst, gibt du dem Konstruktor eine Liste, die er nimmt, um eine Menge zu erzeugen. Das könnte aber genauso gut ein Tupel, ein String oder ein Generatorausdruck sein. Insofern ist deine Aussage oben nicht ganz richtig.

Fragen, wie die nach der Funktionsweise bestimmter Sprachelemente kann man sich meiner Meinung nach am effektivsten selbst erarbeiten, in dem man es einfach im interaktiven Interpreter ausprobiert. Z.B.:

Code: Alles auswählen

In [1]: i = 5

In [2]: i += 2

In [3]: i
Out[3]: 7

In [4]: p = {1, 2, 3, 4, 5}

In [5]: q = {3, 4}

In [6]: p -= q

In [7]: p = set((1, 2, 3))

In [8]: p
Out[8]: {1, 2, 3}

In [9]: p = set(i for i in range(1, 4))

In [10]: p
Out[10]: {1, 2, 3}

In [11]: p = set('abc')

In [12]: p
Out[12]: {'a', 'b', 'c'}

Atalanttore
User
Beiträge: 407
Registriert: Freitag 6. August 2010, 17:03

Sirius3 hat geschrieben: Sonntag 19. August 2018, 21:36 Dieses undokumentierte Vergrößern des Ranges macht für mich aber immer noch keinen Sinn. Wenn die Eingangsliste tatsächlich gleich viele Elemente wie die Ergebnisliste haben soll, dann kann da nicht viel Zufall drin stecken.
Viel Zufall möchte ich durch meine Einschränkungen gerade ausschließen.

nezzcarth hat geschrieben: Sonntag 19. August 2018, 21:58 Es gibt für viele eingebaute Datentypen in Python zwei Arten, diese zu definieren: Einmal über Literale und einmal über Konstruktoren. Die literale Schreibweise für Listen ist '[1,2,3]', für Mengen '{1, 2, 3}' und für Tupel '(1, 2, 3)'. Die Konstruktoren nehmen als Parameter ein Iterable und geben dann einen entsprechend befülltes Objekt des jeweiligen Typs zurück.
Habe ich es richtig verstanden, dass ein "Iterable" entweder eine Liste, eine Menge oder ein Tupel ist, über das man mit einer (for) Schleife iterieren kann?


Gruß
Atalanttore
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Atalanttore: Ein „iterable“ ist *irgendein* Objekt über das man iterieren kann.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Atalanttore
User
Beiträge: 407
Registriert: Freitag 6. August 2010, 17:03

Wieder was gelernt. Danke.

Gruß
Atalanttore
Antworten