Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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:

[email protected]
[email protected]
[email protected]

Would be split into two lists:

Unique
[email protected]

Duplicates
[email protected]
[email protected]

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.

like image 246
Equalsk Avatar asked Dec 19 '22 11:12

Equalsk


2 Answers

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] will be the unique ones and group[1] will be the non-unique ones.

like image 192
D Stanley Avatar answered Dec 20 '22 23:12

D Stanley


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

Alternatively, once you get one list, you can get the other one using Except:

var uniques = list.Except(duplicates);
// or
var duplicates = list.Except(uniques);
like image 41
Arturo Menchaca Avatar answered Dec 20 '22 23:12

Arturo Menchaca