如何使用linq获取具有默认值的有序列表

时间:2011-11-19 17:32:27

标签: c# linq

我有ICollection条记录(userID,itemID,rating)IEnumerable items

对于特定用户ID和来自一组itemID的每个itemID,我需要生成项目的用户评级列表,如果不存在此类记录,则需要生成0。该清单应按物品排序。

示例:

records = [(1,1,2),(1,2,3),(2,3,1)]  
items = [3,1]  
userID = 1

result = [0,2]

我的尝试:

dataset.Where((x) => (x.userID == uID) & items.Contains(x.iID)).Select((x) => x.rating);

它完成了这项工作,但它没有返回0作为默认值而且它没有被命令......

我是C#和LINQ的新手,非常感谢正确方向的指针。 谢谢。

4 个答案:

答案 0 :(得分:0)

怎么样:

dataset.Where((x) => (x.userID == uID)).Select((x) => items.Contains(x.iID) ? x.rating : 0)

答案 1 :(得分:0)

这就是工作:

        var records = new int[][] { new int[] { 1, 1, 2 }, new int[] { 1, 2, 3 }, new int[] { 2, 3, 1 } };
        var items = new int[] { 3, 1 };

        var userId = 1;

        var result = items.Select(i =>
        {
            // When there's a match
            if (records.Any(r => r[0] == userId && r[1] == i))
            {
                // Return all numbers
                return records.Where(r => r[0] == userId && r[1] == i).Select(r => r[2]);
            }
            else
            {
               // Just return 0
                return new int[] { 0 };
            }
        }).SelectMany(r => r); // flatten the int[][] to int[]

        // output
        result.ToList().ForEach(i => Console.Write("{0} ", i));
        Console.ReadKey(true);

答案 2 :(得分:0)

这可以胜任。但是,它是否可维护/可读解决方案是另一个讨论的主题:

// using your example as pseudo-code input
var records = [(1,1,2),(1,2,3),(2,3,1)];
var items = [3,1];
var userID = 1;

var output = items
    .OrderByDescending(i => i)
    .GroupJoin(records, 
               i => i, 
               r => r.ItemId, 
               (i, r) => new { ItemId = i, Records = r})
    .Select(g => g.Records.FirstOrDefault(r => r.UserId == userId))
    .Select(r => r == null ? 0 : r.Rating);

此查询的工作原理......

  • 订购很明显
  • 丑陋GroupJoin - 它将items中的所有元素与共享相同ItemId的所有记录合并为匿名类型{ItemId, Records}
  • 现在我们为匹配userId的每个条目选择第一条记录 - 如果找不到,则会返回null(感谢FirstOrDefault
  • 我们做的最后一件事是检查我们是否有价值(我们选择Rating)或不 - 0

答案 3 :(得分:0)

这个怎么样?您的问题听起来有点像SQL的外部联接,您可以使用GroupJoin,SelectMany执行此操作:

var record1 = new Record() { userID = 1, itemID = 1, rating = 2 };
var record2 = new Record() { userID = 1, itemID = 2, rating = 3 };
var record3 = new Record() { userID = 2, itemID = 3, rating = 1 };

var records = new List<Record>  { record1, record2, record3 };

int userID = 1;
var items = new List<int> { 3, 1 };

var results = items
.GroupJoin( records.Where(r => r.userID == userID), item => item, record => record.itemID, (item, record) => new { item, ratings = record.Select(r => r.rating) } )
.OrderBy( itemRating => itemRating.item)
.SelectMany( itemRating => itemRating.ratings.DefaultIfEmpty(), (itemRating, rating) => rating);

解释发生了什么

  • 对于每个项目,GroupJoin获取指定用户的评级列表(如果没有评级,则为空列表)
  • OrderBy很明显
  • SelectMany会对评级列表进行展平,如果评级列表为空,则提供零(通过DefaultIfEmpty)

希望这是有道理的。

请注意,如果用户对某个项目的评分不止一个,则所有评分都会显示在最终列表中。