Anees Deen
Anees Deen

Reputation: 1413

How to copy a List<> to another List<> with Comparsion in c#

I an having Two Lists. I want to get the matched and unmatched values based on ID and add the results to another List. I can get both of these using Intersect/Except.

But I can get only ID in the resultant variables (matches and unmatches) . I need all the properties in the Template.

List<Template> listForTemplate = new List<Template>();
List<Template1> listForTemplate1 = new List<Template1>();

 var matches = listForTemplate .Select(f => f.ID)
                      .Intersect(listForTemplate1 .Select(b => b.ID));

 var ummatches = listForTemplate .Select(f => f.ID)
                     .Except(listForTemplate1.Select(b => b.ID));

     public class Template
     {
       public string ID{ get; set; }
       public string Name{ get; set; }
       public string Age{ get; set; }
       public string Place{ get; set; }
       public string City{ get; set; }
       public string State{ get; set; }
       public string Country{ get; set; }
     }
     public class Template1
     {
         public string ID{ get; set; }
     }

Upvotes: 5

Views: 595

Answers (5)

Dave R.
Dave R.

Reputation: 7304

If you don't absolutely have to use LINQ, why not code something like this?

    var matches = new List<Template>();
    var unmatches = new List<Template>();

    foreach (var entry in listForTemplate)
    {
        bool matched = false;
        foreach (var t1Entry in listForTemplate1)
        {
            if (entry.ID == t1Entry.ID)
            {
                matches.Add(entry);
                matched = true;
                break;
            }
        }
        if (!matched)
        {
            unmatches.Add(entry);
        }
    }

A disadvantage of the LINQ approach is that you're traversing the lists twice.

Upvotes: 0

Matthew Watson
Matthew Watson

Reputation: 109567

For comparison, this should also work (the first part is a variation on @MAV's answer):

var matches = from item in listForTemplate
              join id in listForTemplate1 on item.ID equals id.ID
              select item;

var unmatches = listForTemplate.Where(item => matches.All(elem => elem.ID != item.ID));

matches and unmatches will both be IEnumerable<Template> which is the type you require.

However, MAV's answer works fine so I'd go for that one.

Upvotes: 1

Ric
Ric

Reputation: 13248

As mentioned, Implement the IEqualityComparer<T> interface.

IEqualityComparer<T> MSDN

Then use this as an argument in your method for Except() and Intersect()

Intersect

There is a good example of how to do so on the link for the Intersect() method.

Upvotes: 0

MAV
MAV

Reputation: 7457

If you don't want to implement IEquality for this simple task, you can just modify your LINQ queries:

var matches = listForTemplate.Where(f => listForTemplate1.Any(b => b.ID == f.ID));

and

var unmatches = listForTemplate.Where(f => listForTemplate1.All(b => b.ID != f.ID));

You might want to check for null before accessing ID, but it should work.

Upvotes: 3

lajos.cseppento
lajos.cseppento

Reputation: 897

You are looking for the overloaded function, with the second parameter IEqualityComparer. So make your comparer ( example: http://www.blackwasp.co.uk/IEqualityComparer.aspx ), and use the same comparer in intersect / except.

And for the generic part: maybe you should have a common interface for templates e.g. ObjectWithID describing that the class have a string ID property. Or simply use dynamic in your comparer (but I think this is very-very antipattern because you can have run time errors if using for the bad type).

You also have a problem: intersecting two collections with two different types will result in a collection of Object (common parent class). Then you have to cast a lot (antipattern). I advise you to make a common abstract class/interface for your template classes, and it is working. If you need to cast the elements back, do not cast, but use the visitior pattern: http://en.wikipedia.org/wiki/Visitor_pattern

Example (good):

    static void Main(string[] args)
    {
        // http://stackoverflow.com/questions/16496998/how-to-copy-a-list-to-another-list-with-comparsion-in-c-sharp

        List<Template> listForTemplate = new Template[] {
            new Template(){ID = "1"},
            new Template(){ID = "2"},
            new Template(){ID = "3"},
            new Template(){ID = "4"},
            new Template(){ID = "5"},
            new Template(){ID = "6"},
        }.ToList();

        List<Template1> listForTemplate1 = new Template1[] {
            new Template1(){ID = "1"},
            new Template1(){ID = "3"},
            new Template1(){ID = "5"}
        }.ToList();

        var comp = new ObjectWithIDComparer();

        var matches = listForTemplate.Intersect(listForTemplate1, comp);
        var ummatches = listForTemplate.Except(listForTemplate1, comp);

        Console.WriteLine("Matches:");
        foreach (var item in matches) // note that item is instance of ObjectWithID
        {
            Console.WriteLine("{0}", item.ID);
        }
        Console.WriteLine();

        Console.WriteLine("Ummatches:");
        foreach (var item in ummatches) // note that item is instance of ObjectWithID
        {
            Console.WriteLine("{0}", item.ID);
        }
        Console.WriteLine();
    }
}

public class ObjectWithIDComparer : IEqualityComparer<ObjectWithID>
{
    public bool Equals(ObjectWithID x, ObjectWithID y)
    {
        return x.ID == y.ID;
    }

    public int GetHashCode(ObjectWithID obj)
    {
        return obj.ID.GetHashCode();
    }
}

public interface ObjectWithID {
    string ID { get; set; }
}

public class Template : ObjectWithID
{
    public string ID { get; set; }
    public string Name { get; set; }
    public string Age { get; set; }
    public string Place { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string Country { get; set; }
}
public class Template1 : ObjectWithID
{
    public string ID { get; set; }
}

Output:

Matches:
1
3
5

Ummatches:
2
4
6

Press any key to continue . . .

Upvotes: 2

Related Questions