找到两个未一起查看的元素的组合(LINQ,SQL或C#)

时间:2009-03-02 02:57:32

标签: c# sql linq linq-to-sql combinations

我有一个显示两个对象的页面,然后用户选择其中一个。我在MSSQL数据库中记录首选项和组合,最终存储如下数据:

UserId=1, BetterObjectId=1, WorseObjectId=2

现在我想避免再次显示对象组合(1,2 / 2,1)。

那么如何生成随机组合以向用户显示不包括以前查看过的组合?

这似乎应该是一个非常简单的问题,但是像大多数程序员一样,我很少睡觉和喝咖啡,所以非常感谢你的帮助: - )

非常天真的方法是这样的(并且所有对此函数的调用都必须包含在检查中,以查看用户是否已经评估nCr的次数,其中n是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),并进行一些更改以反映组合的对称关系。

4 个答案:

答案 0 :(得分:1)

一个解决方案就是:

SELECT TOP 1 i.id item1, i2.id item2 from item i, item i2 
WHERE i.id <> i2.id 
AND (SELECT COUNT(*) FROM Rating WHERE userId=@userId AND FK_ItemBetter=i.id AND FK_ItemWorse=i2.id) = 0
AND (SELECT COUNT(*) FROM Rating WHERE userId=@userId AND FK_ItemBetter=i2.id AND FK_ItemWorse=i.id) = 0
ORDER BY NEWID()

我之前不知道只列出多个FROM表的cross join方法。

答案 1 :(得分:1)

Table Item: ItemId
Table Rating: UserId, ItemId1, ItemId2, WinnerId

如果您需要ItemId1&lt;在评级表中的ItemId2,您只需要检查一次评级表。

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

答案 2 :(得分:0)

假设可用项目列表在数据库中,我将完全在数据库中处理此问题。无论如何,你已经在使用数据库,为什么不在那里完成它?

答案 3 :(得分:0)

如何将所有对象放入队列或堆栈中,然后弹出2和2直到它们为空?