如何从Smalltalk中的集合中获取特定数量的随机元素?

Mar*_*inW 6 random collections smalltalk pharo

如何从集合中优雅地获取特定数量(> 1)的独特,随机元素?

Lea*_*lia 5

请考虑以下代码段

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
Run Code Online (Sandbox Code Playgroud)

一些评论

  • 显式生成器:它显式地使用给定的生成器,即Random我调用的实例aGenerator.出于数学原因,如果您要为您的应用程序获取样本,则所有这些样本都应该在您的程序中使用相同的生成器.此外,这将为您提供额外的优势:保存并稍后恢复seed,您将能够重现系统以前的"随机"行为,这有利于测试.

  • 不检查可用性:代码不检查是否可以获得所需的样本,如果aCollection没有至少anInteger不同的元素,则会出现这种情况.

  • 无类代码:该方法应该去一些类.

例如:

 Random >> sample: anInteger from: aCollection
   | sample |
   sample := Set new: anInteger.
   [sample size = anInteger]
     whileFalse: [ | element |
       element := aCollection atRandom: self.
       sample add: element].
   ^sample asArray
Run Code Online (Sandbox Code Playgroud)

UPDATE

这是另一种方法:

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
Run Code Online (Sandbox Code Playgroud)

评论

通常情况下,当我们想要不经重复地进行采样时,我们也希望在随机选择它们时从集合中删除元素.在这些情况下,经常发生的是已知该集合没有重复.


Uko*_*Uko 3

我认为这看起来或多或少不错,但效率并不高:

yourCollection asSet asOrderedCollection shuffled first: numberOfElements
Run Code Online (Sandbox Code Playgroud)