我有一个显示两个对象的页面,然后用户选择其中一个.我在MSSQL数据库中记录首选项和组合,最终存储如下数据:
UserId=1, BetterObjectId=1, WorseObjectId=2
现在我想避免再次显示对象组合(1,2 / 2,1).
那么如何生成随机组合以向用户显示不包括以前查看过的组合?
这似乎应该是一个非常简单的问题,但像大多数程序员一样,我很少睡觉和喝咖啡,所以你的帮助非常感谢:-)
非常天真的方法是这样的(并且所有对此函数的调用都必须包含在一个检查中,以查看用户是否已经评估nCr的次数,其中n是项目计数,r是2):
public List<Item> GetTwoRandomItems(int userId)
{
Item i = null, i2 = null;
List<Item> r = null;
while (i == null || i2 == null)
{
r = GetTwoRandomItemsRaw();
i = r[0];
i2 = r[1];
if (GetRating(i.Id, i2.Id, userId) != null) /* Checks if viewed */
{
i = null;
i2 = null;
}
}
return r;
}
private List<Item> GetTwoRandomItemsRaw()
{
return Items.ToList().OrderBy(i => Guid.NewGuid()).Take(2).ToList();
}
编辑
使用一些SQL我可以生成一个未完成的所有项目的列表(即,涉及用户尚未看到的项目的组合),但我认为不是特别有用.
我还可以设想在选择2个随机项目之前生成所有可能的组合并消除已经查看的组合,但这是另一个可怕的解决方案.
可能性(对于大n的存储器密集)是生成所有可能的组合并将组合Id存储在评级中.然后我可以对所有组合进行选择WHERE combinationId IS NOT IN(SELECT combinationId FROM ratings WHERE userId = x),并进行一些更改以反映组合的对称关系.
最佳答案
Table Item: ItemId
Table Rating: UserId, ItemId1, ItemId2, WinnerId
如果您需要ItemId1
var pair = db.Items.Join(db.Items,
i1 => i1.ItemId,
i2 => i2.ItemId,
(i1, i2) => new {i1, i2}
) //produce all pairs
.Where(x => x.i1.ItemId < x.i2.ItemId) //filter diagonal to unique pairs
.Where(x =>
!db.Ratings
.Where(r => r.UserId == userId
&& r.ItemId1 == x.i1.ItemId
&& r.ItemId2 == x.i2.ItemId)
.Any() //not any ratings for this user and pair
)
.OrderBy(x => db.GetNewId()) //in-database random ordering
.First(); // just give me the first one
return new List<Item>() {pair.i1, pair.i2 };
这是关于将“随机”翻译成数据库的blog.