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

Random 如何在Smalltalk中从集合中获取特定数量的随机元素?,random,collections,smalltalk,pharo,Random,Collections,Smalltalk,Pharo,如何从一个集合中优雅地获取特定数量(>1)的不同随机元素?这是我认为看起来或多或少不错的东西,但效率不如它: yourCollection asSet asOrderedCollection shuffled first: numberOfElements 考虑下面的代码片段 sample: anInteger from: aCollection using: aGenerator | sample | sample := Set new: anInteger. [sample s

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

这是我认为看起来或多或少不错的东西,但效率不如它:

yourCollection asSet asOrderedCollection shuffled first: numberOfElements

考虑下面的代码片段

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
一些评论

  • 显式生成器:它显式使用给定的生成器,即
    Random
    的实例,我称之为
    aGenerator
    。出于数学上的原因,如果您正在获取应用程序的示例,那么所有这些示例都应该在整个程序中使用相同的生成器。此外,这还将为您提供一个额外的优势:保存并稍后恢复
    种子
    ,您将能够重现系统以前的“随机”行为,这有利于测试

  • 不检查可用性:代码不检查是否有可能获得所需的样本,如果
    a集合
    没有至少
    a整数
    不同的元素,就会出现这种情况

  • 无类代码:该方法应转到某个类

例如:

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

以下是另一种方法:

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
评论


通常情况下,当我们希望不重复地采样时,我们还希望在随机选取元素时将其从集合中移除。在这些情况下,经常发生的情况是,已知收集没有重复。

Hmm,我喜欢“byo生成器”方法,但如果收集和样本量很大,您可能会被困在最后等待相当长的时间,直到生成器最终选择一个“免费”数字。@AmosM.Carpenter这是一个很好的观点。我所使用的方法更接近于第二种方法。很抱歉吹毛求疵,但您不应该使用
\removeIndex:
-这是为了保密。相反,使用公共方法
#removeAt:
将具有回答已删除元素的额外好处,这意味着您可以去掉额外的
元素
临时变量(即只需执行
示例添加:(aCollection removeAt:index)
)。这两种“删除”方法都在OrderedCollection上,因此这不适用于其他类型的集合。@AmosM.Carpenter感谢您的审阅。我不是Pharo程序员,所以我没有意识到
removeIndex:
是私有的。我已根据你的意见修改了方法。是的,该方法只适用于
OrderCollection
(在大多数实际应用中应该可以)非常优雅。我所能看到的提高效率的唯一方法(这通常不是问题,但有些人会对此挂断电话……)是将索引而不是集合(因为索引会更少),然后使用类似于
#atAll:
的方法从集合中挑选那些随机索引(如果您想让它们区别开来,您仍然需要
#asSet
)。