compare two list and return not matching items using linq

Viewed 129326

i have a two list

List<Sent> SentList;
List<Messages> MsgList;

both have the same property called MsgID;

MsgList            SentList  

MsgID Content      MsgID Content Stauts
1       aaa        1       aaa     0
2       bbb        3       ccc     0
3       ccc        
4       ddd
5       eee

i want to compare the MsgID in Msglist with the sentlist and need items which are not in the sent list using linq

Result 

MsgID Content
2       bbb
4       ddd
5       eee
12 Answers

As an extension method

public static IEnumerable<TSource> AreNotEqual<TSource, TKey, TTarget>(this IEnumerable<TSource> source, Func<TSource, TKey> sourceKeySelector, IEnumerable<TTarget> target, Func<TTarget, TKey> targetKeySelector) 
{
    var targetValues = new HashSet<TKey>(target.Select(targetKeySelector));

    return source.Where(sourceValue => targetValues.Contains(sourceKeySelector(sourceValue)) == false);
}

eg.

public class Customer
{
    public int CustomerId { get; set; }
}

public class OtherCustomer
{
    public int Id { get; set; }
}


var customers = new List<Customer>()
{
    new Customer() { CustomerId = 1 },
    new Customer() { CustomerId = 2 }
};

var others = new List<OtherCustomer>()
{
    new OtherCustomer() { Id = 2 },
    new OtherCustomer() { Id = 3 }
};

var result = customers.AreNotEqual(customer => customer.CustomerId, others, other => other.Id).ToList();

Debug.Assert(result.Count == 1);
Debug.Assert(result[0].CustomerId == 1);
List<Person> persons1 = new List<Person>
           {
                    new Person {Id = 1, Name = "Person 1"},
                    new Person {Id = 2, Name = "Person 2"},
                    new Person {Id = 3, Name = "Person 3"},
                    new Person {Id = 4, Name = "Person 4"}
           };


        List<Person> persons2 = new List<Person>
           {
                    new Person {Id = 1, Name = "Person 1"},
                    new Person {Id = 2, Name = "Person 2"},
                    new Person {Id = 3, Name = "Person 3"},
                    new Person {Id = 4, Name = "Person 4"},
                    new Person {Id = 5, Name = "Person 5"},
                    new Person {Id = 6, Name = "Person 6"},
                    new Person {Id = 7, Name = "Person 7"}
           };
        var output = (from ps1 in persons1
                      from ps2 in persons2
                      where ps1.Id == ps2.Id
                      select ps2.Name).ToList();

Person class

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

    public string Name { get; set; }
}

If u wanna Select items of List from 2nd list:

MainList.Where(p => 2ndlist.Contains(p.columns from MainList )).ToList();

make single list and var result = list.GroupBy(x => x.BillId).Where(x => x.Count() == 1).Select(x => x.First());

In .NET 6 you can take advantage of .ExceptBy(), which lets you define which property of the first list to compare the items in the second list by:

List<Message> result = messages
    .ExceptBy(sentList.Select(msg => msg.MsgID), msg => msg.MsgID)
    .ToList();

messages is the first list, whereas a collection of the MsgID properties from sentList is the second list.

Example fiddle here.

Related