Emulieren Pythons random.choice in .NET

8

Pythons Modul 'random' hat eine Funktion random.choice

  

random.choice(seq)
  Liefert ein zufälliges Element aus der nicht leeren Sequenz seq. Wenn seq leer ist, wird IndexError .

erhöht

Wie kann ich das in .NET emulieren?

%Vor%

Edit: Ich habe das vor einigen Jahren als Interviewfrage gehört, aber heute trat das Problem natürlich in meiner Arbeit auf. Die Interviewfrage wurde mit Einschränkungen angegeben.

  • 'die Sequenz ist zu lang, um sie im Speicher zu speichern'
  • 'Sie können die Sequenz nur einmal durchlaufen'
  • 'Die Sequenz hat keine Längen- / Zählmethode' (à la .NET IEnumerable)
Colonel Panic 03.07.2012, 16:06
quelle

7 Antworten

12

Um eine Methode zu erstellen, die die Quelle nur einmal iteriert und nicht temporär Speicher reservieren muss, zählen Sie, wie viele Elemente Sie iteriert haben, und bestimmen Sie die Wahrscheinlichkeit, dass das aktuelle Element das Ergebnis sein soll:

%Vor%

Wenn Sie beim ersten Element sind, ist die Wahrscheinlichkeit 1/1, dass es verwendet werden sollte (da dies das einzige Element ist, das Sie bisher gesehen haben). Wenn Sie am zweiten Element sind, ist die Wahrscheinlichkeit 1/2, dass es das erste Element ersetzen soll usw.

Dies wird natürlich ein bisschen mehr CPU verbrauchen, da es eine Zufallszahl pro Element erzeugt, nicht nur eine einzelne Zufallszahl, um ein Element auszuwählen, wie dasblinkenlight gezeigt hat. Sie können überprüfen, ob die Quelle IList<T> implementiert, wie Dan Tao vorgeschlagen hat, und eine Implementierung verwenden, die die Funktionen verwendet, um die Länge der Auflistung abzurufen und Elemente nach Index abzurufen:

%Vor%

Hinweis: Sie sollten in Erwägung ziehen, die Random -Instanz in die Methode zu senden. Andernfalls erhalten Sie den gleichen zufälligen Startwert, wenn Sie die Methode zwei Mal zu nahe an der Zeit aufrufen, da der Startwert aus der aktuellen Zeit erstellt wird.

Das Ergebnis eines Testlaufs, bei dem eine Zahl aus einem Array ausgewählt wird, die 0 - 9, 1000000 Mal enthält, um zu zeigen, dass die Verteilung der ausgewählten Zahlen nicht verzerrt ist:

%Vor%     
Guffa 03.07.2012, 16:16
quelle
6

Um zu vermeiden, dass Sie die Sequenz zweimal durchlaufen (einmal für die Zählung und einmal für das Element), ist es wahrscheinlich eine gute Idee, Ihre Sequenz in einem Array zu speichern, bevor Sie ihr zufälliges Element erhalten:

%Vor%

BEARBEITEN Implementiert eine sehr gute Idee von Chris Sinclair .

    
dasblinkenlight 03.07.2012 16:10
quelle
1
%Vor%     
Chris 03.07.2012 16:10
quelle
1
%Vor%

oder Erweiterung

%Vor%     
burning_LEGION 03.07.2012 16:12
quelle
1

Ich würde mit Antwort von dasblinkenlight gehen, mit einer kleinen Änderung: Nutzen Sie die Tatsache, dass source bereits sein könnte eine indizierte Sammlung. In diesem Fall müssen Sie wirklich kein neues Array (oder keine neue Liste) auffüllen:

%Vor%

Beachten Sie, dass ich auch die Schnittstelle von der oben genannten Antwort geändert habe, um sie konsistenter zu der Python-Version zu machen, auf die Sie in Ihrer Frage verwiesen haben:

%Vor%

Bearbeiten Ich mag Guffas Antwort sogar noch besser.

    
Dan Tao 03.07.2012 16:14
quelle
0

Nun, hole eine Liste aller Elemente in der Sequenz. Fragen Sie einen Zufallszahlengenerator für den Index, geben Sie die Elemente nach Index zurück. Definieren Sie, welche Sequenz - IEnumerable am offensichtlichsten ist, aber Sie müssen diese in eine Liste materialisieren und dann die Anzahl der Elemente für den Zufallszahlengenerator kennen. Das ist übrigens nicht emulieren, es ist implementieren.

Ist das eine Hausaufgaben-Anfänger-Kurs-Frage?

    
TomTom 03.07.2012 16:09
quelle
0

Angenommen, Sie haben eine Erweiterungsmethode IEnumerable.MinBy :

%Vor%

Die Methode MinBy speichert die Sequenz nicht im Speicher. Sie funktioniert wie IEnumerable.Min und erstellt eine Iteration (siehe MoreLinq oder anderswo )

    
Colonel Panic 04.07.2012 10:59
quelle

Tags und Links