如何将List <t>拆分为两个列表,一个包含所有重复值,另一个包含其余值?

时间:2016-12-01 17:15:59

标签: c# linq list duplicates

我有一个帐户的基本类(为简洁而删除了其他属性):

public class Account
{
    public string Email { get; set; }
}

我有List<T>个这样的帐户。

我可以轻松删除基于电子邮件地址的重复项:

var uniques = list.GroupBy(x => x.Email).Select(x => x.First()).ToList();

名为&#39; uniques&#39;现在只包含基于电子邮件地址的每个帐户中的一个,任何重复的都被丢弃。

我想做一些不同的事情并将列表分成两部分 一个列表仅包含&#39; true&#39;唯一值,另一个列表将包含所有重复项。

例如以下帐户电子邮件列表:

  

unique@email.com
  dupe@email.com
  dupe@email.com

将分为两个列表:

  

唯一
  unique@email.com

     

重复
  dupe@email.com
  dupe@email.com

我已经能够通过使用顶部的示例创建唯一值列表来实现此目的。然后我在原始列表中使用.Except()来获取重复的差异。最后,我可以将每个副本循环到&#39; pop&#39;它出自唯一列表并将其移至重复列表。

Here is a working example on .NET Fiddle

我可以用更高效或符合语法的方式拆分列表吗?

如果有必要,我很乐意使用第三方图书馆,但我宁愿坚持使用纯粹的LINQ。
我知道CodeReview,但觉得问题也适合这里。

3 个答案:

答案 0 :(得分:6)

var groups = list.GroupBy(x => x.Email)
                 .GroupBy(g => g.Count() == 1 ? 0 : 1)
                 .OrderBy(g => g.Key)
                 .Select(g => g.SelectMany(x => x))
                 .ToList();

groups[0]将是唯一的,group[1]将是非唯一的。

答案 1 :(得分:3)

var duplicates = list.GroupBy(x => x) // or x.Property if you are grouping by some property.
                     .Where(g => g.Count() > 1)
                     .SelectMany(g => g);

var uniques = list.GroupBy(x => x) // or x.Property if you are grouping by some property.
                  .Where(g => g.Count() == 1)
                  .SelectMany(g => g);

或者,一旦获得一个列表,您可以使用Except获取另一个列表:

var uniques = list.Except(duplicates);
// or
var duplicates = list.Except(uniques);

答案 2 :(得分:0)

另一种方法是获取唯一身份,然后对于重复项,只需获取原始列表中不属于唯一身份的元素。

IEnumerable<Account> uniques;
IEnumerable<Account> dupes;
dupes = list.Where(d => 
         !(uniques = list.GroupBy(x => x.Email)
                         .Where(g => g.Count() == 1)
                         .SelectMany(u => u))
         .Contains(d));