Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get a specific number of random elements from a collection in Smalltalk?

How can I elegantly get a specific number (>1) of distinct, random elements from a collection?

like image 984
MartinW Avatar asked Feb 26 '16 10:02

MartinW


2 Answers

Consider the following code snippet

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

Some remarks

  • Explicit Generator: It explicitly uses a given generator, i.e., an instance of Random, which I've called aGenerator. For mathematical reasons, if you are getting samples for your application, all of them should use the very same generator across your program. Also this will give you an additional advantage: save and later restore the seed and you will be able to reproduce a previous "random" behavior of your system, which is good for testing.

  • No check for availability: The code doesn't check that it is possible to get the desired sample, which would be the case if aCollection doesn't have at least anInteger different elements.

  • Classless code: The method should go to some class.

For example:

 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

Here is another approach:

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

Comment

It usually happens that when we want to sample without repetition we also want to remove the elements from the collection as we randomly pick them. In these cases what often happens is that the collection is known to have no repetitions.

like image 118
Leandro Caniglia Avatar answered Oct 20 '22 03:10

Leandro Caniglia


This is something that I think looks more or less nice, but is not as efficient as it can be:

yourCollection asSet asOrderedCollection shuffled first: numberOfElements
like image 37
Uko Avatar answered Oct 20 '22 02:10

Uko