Reputation: 1413
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
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
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
Reputation: 13248
As mentioned, Implement the IEqualityComparer<T>
interface.
Then use this as an argument in your method for Except()
and Intersect()
There is a good example of how to do so on the link for the Intersect()
method.
Upvotes: 0
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
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