Linq取得了明显的成就

时间:2012-07-16 20:24:26

标签: c# linq random distinct

我有查询:

var q = (
    from c in db.tblStoreRecommendations
    where
    itemIDsInCart.Contains(c.ItemID)
    && !itemIDsInCart.Contains(c.RecommendItemID)
    select c
);

它将返回以下内容:

ID    ItemID    RecommendItemID    Message
------------------------------------------
1     25        3                  Msg here
2     26        3                  Something else
3     27        8                  Another message

我需要查询来过滤掉具有相同RecommendItemID的结果,这不应该多次出现在返回的结果中。

如果两个存在,它可以使用(随机选择最好)。因此返回的结果应该省略记录ID 1或2。

有人能告诉我该怎么做吗?谢谢!

3 个答案:

答案 0 :(得分:6)

一种方法是使用GroupBy,然后从每个组中选择第一项:

var q = (
    from c in db.tblStoreRecommendations
    where
        itemIDsInCart.Contains(c.ItemID)
     && !itemIDsInCart.Contains(c.RecommendItemID)
    select c
).GroupBy(c => c.RecommendItemID)
 .Select(g => g.First());

如果您使用它来显示随机评论,我建议将其强制使用代码而不是LINQ查询,省略First,如下所示:

var q = (
    from c in db.tblStoreRecommendations
    where
        itemIDsInCart.Contains(c.ItemID)
     && !itemIDsInCart.Contains(c.RecommendItemID)
    select c
).GroupBy(c => c.RecommendItemID)
 .Select(g => g.ToArray());

var random = new Random();
foreach (var r in q)
{
    var rec = r[random.Next(r.Length)];
    // use your recommendation
}

答案 1 :(得分:3)

我相信你可以在你的linq表达式的末尾添加一个明显的比较,比如:

var q = (
  from c in db.tblStoreRecommendations
  where
  itemIDsInCart.Contains(c.ItemID)
  && !itemIDsInCart.Contains(c.RecommendItemID)
  select c
)
.Distinct((x, y) => x.RecommendItemID == y.RecommendItemID);

修改

我刚刚意识到我是使用自己编写的扩展方法完成此操作并且通常保持方便...这里是代码:

    /// <summary>
    /// Provides a way to get a distinct list of items based on a lambda comparison operator.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="source"></param>
    /// <param name="equalityComparer">A comparison function that returns true of the two items are considered equal.</param>
    /// <returns>The list of distinct items.</returns>
    public static IEnumerable<T> Distinct<T>(this IEnumerable<T> source, Func<T, T, bool> equalityComparer)
    {
        var distincts = new List<T>();
        foreach (var item in source)
        {
            var found = false;
            foreach (var d in distincts)
            {
                found = equalityComparer(item, d);
                if (found)
                    break;
            }

            if (!found)
            {
                distincts.Add(item);
                yield return item;
            }
        }
    }

答案 2 :(得分:1)

让我们尽可能地尝试使用查询表达式:

var q = from c in db.tblStoreRecommendations
        where itemIDsInCart.Contains(c.ItemID)
          && !itemIDsInCart.Contains(c.RecommendItemID)
        group c by c.RecommendItemID into matches
        select matches.First();

上下文关键字into肯定会派上用场。

这里是randomize如何:

private static Random random = new Random();

var q = from c in db.tblStoreRecommendations
        where itemIDsInCart.Contains(c.ItemID)
          && !itemIDsInCart.Contains(c.RecommendItemID)
        group c by c.RecommendItemID
        into matches
        select matches.AsEnumerable().ElementAt(random.Next(matches.Count()));

由于LINQ to SQL无法处理ElementAt调用,因此在从分组中选择Random元素之前,我编辑了执行查询的答案(通过调用AsEnumerable)。