如何获得不同的列表类型列表

时间:2014-02-05 23:52:24

标签: c# linq

这是我的代码(如果你愿意,可以将其复制并粘贴到linqpad中)

var messageUsers = new [] { 
    new { MsgId = 2, UserId = 7 },
    new { MsgId = 2, UserId = 8 },
    new { MsgId = 3, UserId = 7 },
    new { MsgId = 3, UserId = 8 },
    new { MsgId = 1, UserId = 7 },
    new { MsgId = 1, UserId = 8 },
    new { MsgId = 1, UserId = 9 }};

messageUsers
    .GroupBy (x => x.MsgId, x => x.UserId)
    .Select (x => x.Select (y => y))
    .Distinct()
    .Dump();

我得到的结果是{7,8},{7,8},{7,8,9}

我想要的是{7,8},{7,8,9}。

基本上我想删除重复的列表。 我没有尝试过这个,但我想我可以通过创建一个比较器并将其传递给Distinct方法来实现。但是我想最终在Linq to Entities查询中使用它,而不会将数千行返回给客户端,因此这不是一个好的选择。

为了进一步说明......我需要返回一个List>其中每个内部列表的内容与任何其他内部列表相比是不同的。

2 个答案:

答案 0 :(得分:4)

问题是.Distinct()根据底层对象的GetHashCode()Equals()实现确定了什么是不同的。在这种情况下,底层对象是实现IEnumerable<>的东西,但是对这些方法使用默认的object实现 - 这完全基于对象是否占用内存中的相同空间。因此,就它所知,序列并不是截然不同的,即使它们具有相同的值。

这个怎么样?

messageUsers
    .GroupBy (x => x.MsgId, x => x.UserId)
    .GroupBy(x => string.Join(",", x))
    .Select(x => x.FirstOrDefault())
    .Dump();

这个想法是按一个键来分组,该键表示列表中元素的组合值。您也可以将自定义IEqualityComparer<>传递给原始代码中的Distinct方法,但这对于一些如此微不足道的事情来说似乎是相当费力的。

值得注意的是,如果您使用LINQ to Entities或类似的东西,这将无法正常工作。

更新

要使其成为List<List<int>>,您需要在其中投放一些.ToList()

messageUsers
    .GroupBy (x => x.MsgId, x => x.UserId)
    .GroupBy(x => string.Join(",", x))
    .Select(x => x.FirstOrDefault().ToList())
    .ToList()
    .Dump();

但我坦率地不确定为什么这对你很重要。

答案 1 :(得分:1)

这是一个替代答案:

messageUsers
    .GroupBy (x => x.MsgId, y=>y.UserId)
    .Select (x => new HashSet<int>(x))
    .Distinct(HashSet<int>.CreateSetComparer())
    .Dump();

考虑以下输入:

var messageUsers = new [] { 
    new { MsgId = 2, UserId = 7 },
    new { MsgId = 2, UserId = 8 },
    new { MsgId = 3, UserId = 8 },
    new { MsgId = 3, UserId = 7 },
    new { MsgId = 1, UserId = 7 },
    new { MsgId = 1, UserId = 8 },
    new { MsgId = 1, UserId = 9 }};

你想要什么结果?

{7,8},{7,8,9}或{7,8},{8,7},{7,8,9}。