Использование Linq пересекаются с под значениями? - PullRequest
1 голос
/ 13 августа 2011

Я нашел этот пост Совпадение элементов между двумя коллекциями с помощью Linq в c # , в котором объясняется, как можно использовать Intersect для поиска совпадающих элементов между двумя списками.

Можно ли использовать это для сопоставления элементовв двух списках, которые не совсем одинаковы, но имеют «вспомогательные значения», которые вы хотите сопоставить?

Мой пример такой: у меня есть две коллекции, каждая из которых содержит списки XElements.Один с элементами с именем <link>, а другой с элементами с именем <file>, каждый имеет атрибуты с именем «путь», и именно этот атрибут я хочу сопоставить.Если атрибут пути равен, я хочу совпадение.

В результирующем наборе я хотел бы получить список всех элементов, пути которых совпадают с путями элементов.

Как это может бытьсделано?

1 Ответ

2 голосов
/ 13 августа 2011

Я бы предложил использовать LambdaComparer , который можно передать в метод Intersect() как Equality Comparer, он позволяет задавать логику сравнения на месте, предоставляя логическое условие, вместо этого каждый раз вводя новый класс сравнения, поэтому Ваш код будет достаточно понятным:

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() реализацию

...