Использование Linq пересекается с подзначениями?

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

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

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

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

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


person Anders    schedule 13.08.2011    source источник
comment
Итак, путь является атрибутом, а не свойством объекта? Кстати, вы знаете о LambdaComparer?   -  person sll    schedule 13.08.2011
comment
возможный дубликат пересекает два списка с разными объектами   -  person Charles Burns    schedule 28.04.2015


Ответы (1)


Я бы предложил использовать 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()

person sll    schedule 13.08.2011
comment
Каково значение o в GetHashCode(o) в вашем новом предложении? - person Jerry Liang; 13.07.2013
comment
Текущая ссылка на LambdaComparer. - person Gert Arnold; 25.02.2017