2016-02-26 12 views

Odpowiedz

2

To jest coś, co myślę, że wygląda bardziej lub mniej ładne, ale nie jest tak efektywny, jak to może być:

yourCollection asSet asOrderedCollection shuffled first: numberOfElements 
+0

Bardzo elegancki. Jedyny sposób, jaki mogłem zaobserwować, aby poprawić efektywność (która zazwyczaj nie byłaby problemem, ale niektórzy ludzie się na niej odwalali ...) to przetasowanie _indices_ zamiast kolekcji (ponieważ byłoby mniej indeksów) , a następnie użyj czegoś takiego jak '#atAll:', aby wybrać te losowe indeksy ze zbioru (nadal potrzebujesz '# asSet', jeśli chcesz je _distinct_). –

5

Rozważmy następujący fragment kodu

sample: anInteger from: aCollection using: aGenerator 
    | sample | 
    sample := Set new: anInteger. 
    [sample size = anInteger] 
    whileFalse: [ | element | 
     element := aCollection atRandom: aGenerator. 
     sample add: element]. 
    ^sample asArray 

Kilka uwag

  • Wyraźny generator: To jawnie używa danego generatora, tj. Instancji o numerze Random, którą nazwałem aGenerator. Ze względów matematycznych, jeśli pobierasz próbki do swojej aplikacji, wszystkie powinny używać tego samego generatora w całym programie. Zapewni to także dodatkową korzyść: zapisz i później przywróć wersję seed, a będziesz w stanie odtworzyć poprzednie "losowe" zachowanie systemu, co jest dobre do testowania.

  • No check dostępność: kod nie sprawdza, że ​​jest możliwe, aby uzyskać żądaną próbkę, co byłoby, gdyby aCollection nie posiada przynajmniej anInteger różnych elementów.

  • Kod bez kodowania: Metoda powinna trafić do niektórych klas.

Na przykład:

Random >> sample: anInteger from: aCollection 
    | sample | 
    sample := Set new: anInteger. 
    [sample size = anInteger] 
    whileFalse: [ | element | 
     element := aCollection atRandom: self. 
     sample add: element]. 
    ^sample asArray 

UPDATE

Oto innego podejścia:

Random >> remove: anInteger from: aCollection 
    | sample | 
    sample := OrderedCollection new: anInteger. 
    anInteger timesRepeat: [| index element | 
    index := aCollection size atRandom: self. 
    element := aCollection removeAt: index. 
    sample add: element]. 
    ^sample 

Komentarz

Zwykle, gdy chcemy próbkować bez powtórzeń, chcemy również usunąć elementy z kolekcji, ponieważ losowo je wybieramy. W takich przypadkach często zdarza się, że zbiór nie zawiera powtórzeń.

+1

Hmm, podoba mi się podejście "byo generator", ale jeśli kolekcja i rozmiar próbki są duże, możesz zostać zablokowany w oczekiwaniu na chwilę, aż generator ostatecznie wybierze "wolny" numer. –

+0

@ AmosM.Carpenter dobry punkt. To, czego używam, jest bliższe drugiemu podejściu. –

+1

Przepraszam za bycie prymitywnym, ale nie powinieneś używać '#removeIndex:' - to ma być prywatne. Używanie publicznej metody '#removeAt:' zamiast tego miałoby dodatkową korzyść w postaci odpowiedzi na usunięty element, co oznacza, że ​​możesz pozbyć się dodatkowej zmiennej tymczasowej 'element' (tj. Po prostu wykonaj' sample add: (aCollection removeAt: index) ') .Obie te metody "usuwania" znajdują się w 'OrderedCollection', więc nie będzie działać z innymi typami kolekcji. –

Powiązane problemy