randint -- ohne doppelte Zahlen

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
acidk
User
Beiträge: 75
Registriert: Samstag 6. Januar 2007, 18:54
Wohnort: Braunschweig

Hallo Pythongemeinde!

Ich möchte mir ca. 100 Zufallszahlen (ganzzahlig) aus einem Zahlenraum von 1- 1000 ausgeben lassen --- ohne dass eine Zahl doppelt ist.
randint() bringt leider doppelte Einträge mit.

Kennt jemand von Euch eine bereits implementierte Methode des Ziehens ohne Zurücklegens?
Ansonsten : selbst eine Liste erzeugen, Zufallszahl ziehen und die Ausgangsliste sukzessiv verkleinern!?

Danke & Gruß,

flo
Benutzeravatar
str1442
User
Beiträge: 520
Registriert: Samstag 31. Mai 2008, 21:13

Code: Alles auswählen

>>> random.sample(range(1, 1001), 100)
[753, 336, 341, 636, 101, 231, 484, 97, 372, 414, 200, 653, 218, 116, 831, 109, 862, 454, 118, 722, 772, 100, 937, 902, 39, 502, 954, 611, 228, 233, 906, 864, 509, 729, 975, 574, 282, 979, 761, 205, 359, 494, 338, 635, 571, 84, 148, 935, 213, 889, 885, 374, 78, 921, 681, 515, 464, 63, 493, 508, 992, 489, 543, 824, 783, 853, 964, 619, 430, 329, 872, 899, 626, 435, 850, 555, 562, 999, 117, 346, 602, 91, 918, 119, 731, 893, 914, 355, 300, 776, 276, 704, 690, 437, 683, 353, 867, 66, 616, 762]
BlackJack

@str1442: Unter Python <3 vielleicht besser `xrange()`, dann muss keine Liste angelegt werden. Bei 1000 Elementen geht das ja noch, aber es skaliert halt nicht gut. :-)
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

@BlackJack: python <3 ich auch :twisted:
the more they change the more they stay the same
Benutzeravatar
str1442
User
Beiträge: 520
Registriert: Samstag 31. Mai 2008, 21:13

Das hatte ich zuerst auch so, wollte den Quelltext aber Python 3 idiomatisch halten, obwohl ich momentan nur 2.5 & 2.6 benutze - ich nahm an, inzwischen sei das ziemlicher Standard, damit niemand von den unterschiedlichen Versionen verwirrt wird / man nicht ewig auf die Versionsgeschichte eingehen muss? Ausnahme, wenn derjenige selbst Python < 3 benutzt oder man es explizit erwähnt.
BlackJack

@str1442: Also ich gehe immer davon aus, dass es sich um Python 2.x dreht solange nichts anderes gesagt wird oder es aus dem Quelltext wirklich deutlich ersichtlich ist. Python 3.x empfinde ich halt als unbrauchbar für den produktiven Einsatz. Es fehlen (für mich zumindest) wichtige Bibliotheken und 3 ist AFAIK noch bei keiner Linuxdistribution die Standardversion.
bords0
User
Beiträge: 234
Registriert: Mittwoch 4. Juli 2007, 20:40

BlackJack hat geschrieben:@str1442: Unter Python <3 vielleicht besser `xrange()`, dann muss keine Liste angelegt werden. Bei 1000 Elementen geht das ja noch, aber es skaliert halt nicht gut. :-)
Wird random.sample dann nicht selbst eine Liste anlegen?
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Ja, aber eine andere. Man benoetigt ja nur n Elemente und dafuer den Platz von 2n zu belegen ist reichlich unnoetig.
BlackJack

@bords0: `random.sample()` wird keine zusätzliche Liste mit *allen* Zahlen anlegen. Wozu auch?

Ich zitiere hier mal den Docstring -- bitte besonders auf den letzten Absatz achten:

Code: Alles auswählen

n [1389]: random.sample?
Type:           instancemethod
Base Class:     <type 'instancemethod'>
String Form:    <bound method Random.sample of <random.Random object at 0x81eb794>>
Namespace:      Interactive
File:           /home/bj/random.py
Definition:     random.sample(self, population, k)
Docstring:
    Chooses k unique random elements from a population sequence.

    Returns a new list containing elements from the population while
    leaving the original population unchanged.  The resulting list is
    in selection order so that all sub-slices will also be valid random
    samples.  This allows raffle winners (the sample) to be partitioned
    into grand prize and second place winners (the subslices).

    Members of the population need not be hashable or unique.  If the
    population contains repeats, then each occurrence is a possible
    selection in the sample.

    To choose a sample in a range of integers, use xrange as an argument.
    This is especially fast and space efficient for sampling from a
    large population:   sample(xrange(10000000), 60)
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Ja, bei *extrem großen* Wertebereichen spielt `xrange()` tatsächlich seine Stärke aus. Das zeigt sich auch sehr deutlich, wenn man an das Beispiel aus der Doku noch eine Null dranhängt.
bords0
User
Beiträge: 234
Registriert: Mittwoch 4. Juli 2007, 20:40

BlackJack hat geschrieben:Ich zitiere hier mal den Docstring -- bitte besonders auf den letzten Absatz achten:
Danke - docstring lesen hätte hier wirklich geholfen...
Ich hatte - naiv - erwartet, dass sample mit beliebigen (endlichen) iterables funktioniert. Verlangt werden aber sequences (__len__ und __getitem__ (ohne slices) reichen aus).

Code: Alles auswählen

import random
class R(object):
    def __init__(self, n):
        self.n = n
    def __len__(self):
       return self.n
    def __getitem__(self, i):
       return i
       
print random.sample(R(10000000), 60)

Code: Alles auswählen

[5280304, 2146322, 6204070, 4886913, 2718223, 4380233, 4221235, 6118917, 9844575, 9696442, 9128220, 8143202, 8026412, 5773508, 3330574, 6575526, 6544951, 6845380, 5935171, 4709120, 9104670, 3812544, 1222064, 5548997, 9788092, 5804768, 8285612, 5397606, 2096968, 5282663, 9971843, 2917535, 3298974, 5330993, 9804053, 7262250, 5434644, 6456028, 9664188, 6054484, 9446025, 2895681, 1142644, 4629462, 6666284, 8197343, 2127831, 1868123, 1604313, 2584585, 6243585, 7276640, 832201, 5698673, 9787499, 4696277, 3647415, 5245245, 2465056, 9532502]
Bei beliebigen iterables müsste man erst mal eine Liste erstellen, da man ja nicht mal weiß, wie groß die Population ist. Bei xrange hat man die Länge und kann auf einzelne Elemente zugreifen - das reicht aus, auch wenn man keine "echte" sequence hat.
Benutzeravatar
HerrHagen
User
Beiträge: 430
Registriert: Freitag 6. Juni 2008, 19:07

@acidk: Bei solchen Dingen auch immer recht nützlich: random.shuffle.

Code: Alles auswählen

>>> import random
>>> l = range(10)
>>> l
0: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> random.shuffle(l)
>>> l
1: [9, 7, 5, 2, 1, 8, 3, 0, 6, 4]
>>> l.pop()  # Ziehen
2: 4
>>> 
acidk
User
Beiträge: 75
Registriert: Samstag 6. Januar 2007, 18:54
Wohnort: Braunschweig

:D Vielen, vielen Dank!!
Antworten