Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add List<> To Another List<> by filtering

Tags:

c#

.net

list

I have one model class:

public class Person 
{
    public int Id { get; set; }
    public string Name { get; set; }
}

When I adding two list with this:

List<Person> people1 = new List<Person> {
    new Person() { Id = 1, Name = "Name1" },
    new Person() { Id = 2, Name = "Name2" },
    new Person() { Id = 3, Name = "Name3" },
};

List<Person> people2 = new List<Person> {
    new Person() { Id = 1, Name = "Name1" },
    new Person() { Id = 4, Name = "Name4" },
    new Person() { Id = 5, Name = "Name5" },
};

people1.AddRange(people2);

If person in people2 has the same id in person in people1, I don't want it added. How can I do that?

like image 605
Qwe Qwe Avatar asked Dec 03 '22 09:12

Qwe Qwe


1 Answers

You can use LINQ for this fairly easily but inefficiently:

people1.AddRange(people2.Where(p2 => !people1.Any(p1 => p1.Id == p2.Id)));

Or you could create a set of IDs first:

HashSet<int> people1Ids = new HashSet<int>(people1.Select(p1 => p1.Id));
people1.AddRange(people2.Where(p2 => !people1Ids.Contains(p2.id));

The first approach is obviously simpler, but if your lists get large, it could become slow, because for every element in people2, it'll look through every element in people1.

The second approach will be significantly faster if people1 is large. If it's people2 that's large instead, you won't get much benefit. For example, if people1 only contains a couple of people, then looking in a hash set for an ID won't be much faster than looking through the list.

You could take an entirely different approach though. If you make your Person type implement IEquatable<Person> based on ID - or create an IEqualityComparer<Person> that does so, and if you don't so much need the existing list to be modified, so much as you need "the union of the two lists", and if you don't care about the order, and if all the entries in each list are unique or you don't mind duplicates being removed, you could just use:

// Specify the comparer as another argument if you need to.
// You could call ToList on the result if you need a list.
var union = people1.Union(people2);

(That's a lot of conditions for that solution, but they may well all be valid.)

like image 125
Jon Skeet Avatar answered Dec 21 '22 15:12

Jon Skeet