这是我的代码(如果你愿意,可以将其复制并粘贴到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>其中每个内部列表的内容与任何其他内部列表相比是不同的。
答案 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}。