LINQ-比较&更新值

时间:2009-12-13 15:28:50

标签: c# linq

可能这个问题之前已经被问过了,但是我的google-fu和SO-Search并没有让我得到我想要的东西。

我有一个自定义类,以及一个用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
 }

在代码的主要部分我有2个列表“source”和“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 };

我想做什么

  1. 更新源列表仅包含sam和andy,因为bob和thomas不在目标列表中。我这样做了

    source =(来自p in source where(from t in target select t)           .Contains(p,new PersonComparer())           选择p).ToList();

  2. 在目标中我应该“标记”sam2并且andy为true而jane默认标记为“false”,我不应该更改它。

  3. 我尝试过使用它,但这会从目标

    中删除“jane”
    //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();
    

    任何LINQ大师能否告诉我我做错了什么?

    3.有更好的方法来编写查询1吗?

    4.最后一个小问题:你怎么说“=&gt;”当你通过电话与同事谈话时

4 个答案:

答案 0 :(得分:2)

Linq并不打算更新列表,因为它在IEnumerable<T>上运行。您可以根据表示所需集合的源和目标创建新的可枚举。

这样的事情应该有效:

var combined = source.Where(x => target.Any(y => y == x))

答案 1 :(得分:2)

正如桑德指出的那样,LINQ用于查询,而不是更新。

然而,回答问题......

的原始查询
source = (from p in source where (from t in target select t)
    .Contains(p, new PersonComparer()) select p).ToList();

更简单地写成:

source = source.Intersect(target, new PersonComparer()).ToList();

话虽如此,您需要将PersonComparer更新为recursive。它应该是这样的:

public int GetHashCode(Person obj)
{
    return obj == null ? 0 
         : StringComparer.OrdinalIgnoreCase.GetHashCode(obj.Name);
}

我恐怕我不太了解你的第二个查询...但如果你想改变现有的对象,我建议使用foreach循环而不是尝试使用LINQ。有副作用的查询通常是个坏主意。

可能意思是:

// 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;
    }
}

答案 2 :(得分:1)

对于第4部分。=&gt;可以理解为goes to

答案 3 :(得分:1)

GetHashCode()方法应该使用obj传递的实例,而不是它自己的父实例。