我正在使用MVC C#和SQL Sever。
我有大约100件物品,我从中选择了2件随机物品。这是一个新的指导直接排序。
vm = vm.OrderBy(c => Guid.NewGuid()).Take(2).ToList();
但是现在我希望能够标记一个项目的子集,以便选择更高的百分比(20%),然后在更晚的时候将另一个子集标记为50%。
项目列表是静态的。它总是大约100件。
我只是打算强制它并将所选项目的20%以上添加到列表中,然后他们只进行两次随机选择。
vm1 = vm.OrderBy(c => Guid.NewGuid()).Take(1).Single();
vm2 = vm.OrderBy(c => Guid.NewGuid()).Where(_ => _.Id != firstSelectedID).Take(1).Single();
但是我认为在SQL中可能会有一种更清晰,更高效的方式或者我在C#中缺少的东西
答案 0 :(得分:0)
有一种纯粹的TSQL方式,你可以在C#中以相同的方式编写它,但我不知道如何通过实体框架来实现它。
declare @table table ( letter nchar(1), weight int)
insert into @table values ('A', 1)
insert into @table values ('B', 2)
insert into @table values ('C', 3)
insert into @table values ('D', 4)
insert into @table values ('E', 5)
declare @total int;
select @total = sum(weight) from @table
declare @selected int;
set @selected = rand() * @total
select @selected
select top 1 * from (
select letter, weight, runningTotal = sum(weight) over (order by letter)
from @table
) data where runningTotal > @selected order by runningTotal
你会得到'E'5个牌,因为它会返回'A'。这大致基于https://en.wikipedia.org/wiki/Fitness_proportionate_selection您可以使用任何可以为您加权的过程替换权重列。
你可以运行
select letter, weight, runningTotal = sum(weight) over (order by letter)
from @table
了解数据的加权方式。
以下版本更好,因为它在一次操作中完成所有操作,但我将副本留在上面,因为它更清楚发生了什么。
select top 1 * from (
select letter, weight, runningTotal = sum(weight) over (order by letter)
from @table
) data where runningTotal > rand() * (select sum(weight) from @table) order by runningTotal