使用Linq与子值相交?

时间:2011-08-13 10:06:00

标签: c# .net linq c#-4.0 intersect

我发现这篇文章Match elements between 2 collections with Linq in c#解释了如何使用Intersect查找两个列表之间的匹配元素。

您是否可以使用它来匹配两个不完全相同但具有您想要匹配的“子值”的列表中的元素?

我的例子是这样的:我有两个集合,每个集合都包含XElements列表。一个名为<link>的元素和另一个名为<file>的元素,每个元素都有一个名为“path”的属性,这是我想要匹配的属性。如果path属性相等,我想要一个匹配。

在结果集中,我想要一个路径与元素路径匹配的所有元素的列表。

如何做到这一点?

1 个答案:

答案 0 :(得分:2)

我建议使用可以作为Equality Comparer传递给Intersect()方法的LambdaComparer,它允许通过提供布尔条件来指定比较逻辑,而不是每次都引入一个新的比较器类,所以你的代码足够清晰:

firstCollection.Intersect(
              secondCollection, 
              new LambdaComparer<YourClass>(
                  (item1, item2) => item1.PropertyName == item2.PropertyName));


 // Below are lists and User class which demonstrates LambdaComparer and Intersect()
 public class User
 {
      public string Name { get; set; }
 }

 IList<User> list1 = new List<User> 
       { 
          new User {Name = "A"}, 
          new User { Name = "B"}
       };
 List<User> list2 = new List<User> 
      { 
          new User {Name = "C"}, 
          new User { Name = "B"}
      };

 var resultSet = list1.Intersect<User>(
         list2, 
         new LambdaComparer<User>((item1, item2) => item1.Name == item2.Name));

基本上,如果您需要比较cusotm属性,您仍然可以将此逻辑封装到

Func<User, User, bool> userNameComparer = (user1, user2) =>
{
 // check attributes using user1.GetType().GetCustomAttributes()
};

然后使用这个比较器功能:

   var resultSet = list1.Intersect<User>(
                     list2, 
                     new LambdaComparer<User>((item1, item2) => userNameComparer));

编辑:请注意本回答中引用的特定问题 可能存在一个问题,默认情况下哈希函数是硬编码的0

6  public LambdaComparer(Func<T, T, bool> lambdaComparer) :
7                this(lambdaComparer, o => 0)
8            {
9            }

在某些情况下,这会导致性能问题,因此我建议将其重构为:

public LambdaComparer(Func<T, T, bool> lambdaComparer) :
                this(lambdaComparer, 
                      EqualityComparer<T>.Default.GetHashCode(o))
            {
            }

所以它将使用内置的GetHashCode()实现