Reputation: 11626
Probably this question was already asked before, but my google-fu and SO-Search did not get me what what I was looking for.
I have a custom class, and a custom class comparer (for checking the equality of the class) implemented with IEqualityComparer.
public class Person
{
public string Name { get; set; }
public bool Flag { get; set; }
}
public class PersonComparer : IEqualityComparer<Person>
{
#region IEqualityComparer<Person> Members
public bool Equals(Person x, Person y)
{
//case insensitive compare
return string.Equals(x.Name, y.Name, StringComparison.OrdinalIgnoreCase);
}
public int GetHashCode(Person obj)
{
return base.GetHashCode();
}
#endregion
}
and in the main portion of the code I have 2 lists "source" and "target"
Person bob = new Person() { Name = "Bob" };
Person sam = new Person() { Name = "Sam" };
Person andy = new Person() { Name = "Andy" };
Person thomas = new Person() { Name = "Thomas" };
Person jimmy = new Person() { Name = "Jimmy" };
Person sam2 = new Person() { Name = "sam" }; // note the lower case
Person jane = new Person() { Name = "Jane" };
List<Person> source = new List<Person>() { bob, sam, andy, thomas };
List<Person> target = new List<Person>() { sam2, andy,jane };
what I want to do
update source list to only contain sam and andy, as bob and thomas are not in the target list. I did this
source = (from p in source where (from t in target select t) .Contains(p, new PersonComparer()) select p).ToList();
In the target I should "Flag" sam2 and andy to true and jane is flagged as "false" by default, I should not change it.
I tried using this, but this removes "jane" from target
//sets sam2 & andy to true, removes Jane
target = (from p in target.Select(t => { t.Flag = true; return t; })
where (from s in source
select s).Intersect(select p).ToList();
Can any LINQ guru tell me what I am doing wrong ?
3.Is there a better way to write Query 1 ?
4.And finally a trivial question: how exactly do you say "=>" when you are talking to a fellow coder over the phone
Upvotes: 0
Views: 691
Reputation: 1499770
As Sander has pointed out, LINQ is for querying, not updating.
However, to answer the questions... Your original query of
source = (from p in source where (from t in target select t)
.Contains(p, new PersonComparer()) select p).ToList();
would be much more simply written as:
source = source.Intersect(target, new PersonComparer()).ToList();
Having said that, you need to update PersonComparer as recursive
mentioned. It should be something like this:
public int GetHashCode(Person obj)
{
return obj == null ? 0
: StringComparer.OrdinalIgnoreCase.GetHashCode(obj.Name);
}
I'm afraid I don't really understand your second query particularly well... but if you want to change the existing objects, I'd suggest a foreach
loop instead of trying to use LINQ. Queries with side-effects are generally a bad idea.
You may mean something like:
// You may want to make some singleton instance available, as this has no state
PersonComparer comparer = new PersonComparer();
foreach (Person person in target)
{
if (source.Contains(person, comparer))
{
person.Flag = true;
}
}
Upvotes: 2
Reputation: 21615
Linq isn't meant to update list, because it operates on IEnumerable<T>
. You can create a new enumerable, based on source and target that represents the collection you need.
Something like this should work:
var combined = source.Where(x => target.Any(y => y == x))
Upvotes: 2
Reputation: 86074
The GetHashCode()
method should use the the obj
passed instance, not its own parent.
Upvotes: 1