Random 如何在Smalltalk中从集合中获取特定数量的随机元素?
如何从一个集合中优雅地获取特定数量(>1)的不同随机元素?这是我认为看起来或多或少不错的东西,但效率不如它: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
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
)。