Equalsk Equalsk - 9 days ago 5
C# Question

How can I split a List<T> into two lists, one containing all duplicate values and the other containing the remainder?

I have a basic class for an Account (other properties removed for brevity):

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


I have a
List<T>
of these accounts.

I can remove duplicates based on the e-mail address easily:

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


The list named 'uniques' now contains only one of each account based on e-mail address, any that were duplicates were discarded.

I want to do something a little different and split the list into two.

One list will contain only 'true' unique values, the other list will contain all duplicates.

For example the following list of Account e-mails:


unique@email.com

dupe@email.com

dupe@email.com


Would be split into two lists:


Unique

unique@email.com

Duplicates

dupe@email.com

dupe@email.com


I have been able to achieve this already by creating a list of unique values using the example at the top. I then use
.Except()
on the original list to get the differences which are the duplicates. Lastly I can loop over each duplicate to 'pop' it out of the unique list and move it to the duplicate list.

Here is a working example on .NET Fiddle

Can I split the list in a more efficient or syntactically sugary way?

I'd be happy to use a third party library if necessary but I'd rather just stick to pure LINQ.

I'm aware of CodeReview but feel the question also fits here.

Answer
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);