在 C# 中按权重选择随机元素的最简洁方法是什么?
让我们假设:
List
哪个元素是:
public class Element {
int Weight { get; set; }
}
我想要实现的是,通过权重随机选择一个元素。 例如:
Element_1.Weight = 100;
Element_2.Weight = 50;
Element_3.Weight = 200;
因此
Element_1
被选中的几率为 100/(100+50+200)=28.57%Element_2
被选中的几率为 50/(100+50+200 )=14.29%Element_3
被选中的几率为 200/(100+50+200)=57.14%
我知道我可以创建一个循环、计算总计等...
我想了解的是,通过 Linq 在一行(或尽可能短)中执行此操作的最佳方法是什么,谢谢。 >
更新
我在下面找到了答案。我学到的第一件事是:Linq 并不神奇,它比精心设计的循环慢。
所以我的问题变成按重量找到一个随机元素(没有尽可能短的东西:)
Lets assume:
List<element>
which element is:
public class Element {
int Weight { get; set; }
}
What I want to achieve is, select an element randomly by the weight.
For example:
Element_1.Weight = 100;
Element_2.Weight = 50;
Element_3.Weight = 200;
So
- the chance
Element_1
got selected is 100/(100+50+200)=28.57% - the chance
Element_2
got selected is 50/(100+50+200)=14.29% - the chance
Element_3
got selected is 200/(100+50+200)=57.14%
I know I can create a loop, calculate total, etc...
What I want to learn is, whats the best way to do this by Linq in ONE line (or as short as possible), thanks.
UPDATE
I found my answer below. First thing I learn is: Linq is NOT magic, it's slower then well-designed loop.
So my question becomes find a random element by weight, (without as short as possible stuff :)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
如果您想要一个通用版本(对于与(单例)随机化助手一起使用很有用,请考虑是否需要常量种子)
用法:
代码:
If you want a generic version (useful for using with a (singleton) randomize helper, consider whether you need a constant seed or not)
usage:
code:
这是一种带有预计算的快速解决方案。预计算需要
O(n)
,搜索需要O(log(n))
。预计算:
生成:
但如果列表在每次搜索之间发生变化,您可以使用简单的
O(n)
线性搜索:This is a fast solution with precomputation. The precomputation takes
O(n)
, the searchO(log(n))
.Precompute:
To generate:
But if the list changes between each search, you can instead use a simple
O(n)
linear search:这可行:
基本上,为每个元素创建一个带有最终权重的分区。
在您的示例中,Element1 将关联到 (1-->100),Element2 关联到 (101-->151) 等等...
然后计算随机权重总和,我们查找关联的范围到它。
您还可以计算方法组中的总和,但这会引入另一个副作用...
请注意,我并不是说这很优雅或很快。但它确实使用了 linq (不是一行......)
This could work:
Basically, for each element a partition is created with an end weight.
In your example, Element1 would associated to (1-->100), Element2 associated to (101-->151) and so on...
Then a random weight sum is calculated and we look for the range which is associated to it.
You could also compute the sum in the method group but that would introduce another side effect...
Note that I'm not saying this is elegant or fast. But it does use linq (not in one line...)
.Net 6 引入了 .Max,使这变得更加容易。
现在可以将其简化为以下一行:
如果权重很大或为浮点数,则效果最好,否则会发生冲突,可以通过将权重乘以某个因子来防止冲突。
.Net 6 introduced .MaxBy making this much easier.
This could now be simplified to the following one-liner:
This works best if the weights are large or floating point numbers, otherwise there will be collisions, which can be prevented by multiplying the weight by some factor.