2017-02-17 1 views
1

У меня есть два спискабыстрый способ получить соответствующие элементы из списка два C#

List1 только две собственности. Cant use Dictionary, так как могут быть дубликаты ключей. Комбинация Property1 и Property2 уникальна.

public class List1 
{ 
    public string Property1 { get; internal set; } 
    public string Property2 { get; internal set; } 
} 

public class List2 
{ 
    public string Property1 { get; internal set; } 
    public string Property2 { get; internal set; } 
    public string Property3 { get; internal set; } 
} 

List<List1> mylist1 = new List<List1>() { 
    new List1() {Property1="664",Property2="Ford" }, 
    new List1() {Property1="665",Property2="Ford" }, 
    new List1() {Property1="664",Property2="Toyota" }, 
}; 

List<List2> mylist2 = new List<List2>() { 
    new List2() {Property1="664",Property2="Ford" ,Property3="USA"}, 
    new List2() {Property1="665",Property2="Ford" ,Property3="USA"}, 
    new List2() {Property1="664",Property2="Toyota" ,Property3="USA"}, 
    new List2() {Property1="666",Property2="Toyota" ,Property3="USA"}, 
}; 

Мне нужно получить соответствующие элементы в mylist1 и mylist2. Матч должен происходить только на Property1 и Property2. Свойство3 в mylist2 можно игнорировать во время сравнения.

В настоящее время я использую

var matchingCodes = mylist1.Where(l1 => mylist2.Any(l2 => (l2.Property1 == l1.Property1 && l2.Property2==l1.Property2))).ToList(); 

, который работает прекрасно. Но есть ли лучший способ/самый быстрый способ сделать это?

Я могу изменить List1 на любой другой тип. но не List2.

+0

Давайте формат последовательных абзацев – Paparazzi

+0

LINQ редко наиболее perfomant варианта – Paparazzi

ответ

2

Вы пытаетесь сделать операции set в своих списках данных в LINQ. Существует четыре вызова функций LINQ, которые вы можете использовать, чтобы сделать текущий код более чистым, а также сжатым. Эти операции являются:

  • Кроме
  • Союза
  • Intersect
  • Distinct

Тот, который вы ищете, Intersect который

Возвращает набор значений найдено t одинаковым в двух отдельных коллекциях Source

Наконец, если вы всегда будете использовать эти специфические свойства для определения равенства и/или уникальность вам нужно будет переопределить Equals для List1 и/или классов list2. Это будет зависеть от того, кто рассматривается в левой части Интерсекта (переменная до.) И кто находится справа от Интерсекта (переменная, переданная в функцию).

Here is a SO answer как переопределить функцию Equals, если вы не знаете, как это сделать. Кстати, у него также есть пример Intersect.

+0

Для OP однако для этого потребовалось бы выполнение пользовательской 'IEqualityComparer '. Совместные решения на основе анонимного типа намного проще и гибки. –

+0

Я редактировал это, когда перед тем, как я увидел комментарий. Должно быть там сейчас. Хотя я пошел по Равенству. Кроме того, его спросили, есть ли «лучший» способ сделать это. Это очень самоуверенное мнение, так как его легче читать в коде, чем все ответы «join». –

0

Оба свойства являются строками, так что вы можете просто создать словарь с ключом к конкатенации этих свойств со значением фактического пунктом.

Таким образом, для каждого элемента в другом списке, вы можете просто посмотреть в словаре для конкатенации их собственности, если есть совпадение, сравнить с находкой

+0

Я не могу отдать должное в другом месте, поэтому ... Самые быстрые ** подходы должны быть такими, а предлагаемые с помощью Sets. Наборы чище, но у вас есть два разных типа объектов - если вы можете обойти это - используйте наборы. Не забудьте переопределить GetHashcode. То, что я предлагаю, должно быть таким же быстрым и не потребовало бы внесения изменений в фактические классы. Я не могу привести пример - у меня нет VS, установленного на этой машине –

3

Самым простым способом сделать это в Linq, который относительно быстро, или по крайней мере быстрее, чем ваш подход использует Join или GroupJoin так:

List<List1> matchingCodes = mylist1.GroupJoin(mylist2, 

       l1 => new { l1.Property1, l1.Property2 },// Define how the key from List1 looks like 
       l2 => new { l2.Property1, l2.Property2 },// Define how the key from List2 looks like 

       // Define what we select from the match between list1 and list2 
       (l1Item, l2Items) => l1Item).ToList(); 

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

GroupJoin работает лучше здесь, так как он дает вам элемент из списка1 и все совпадения из списка2.

Обычный Join вернет тот же самый элемент из списка 1 в соответствие с List2.

Смотрите также Enumerable.GroupJoin (C# Reference)

Примечание это эквивалентно @octavioccl's answer. Также этот пример предполагает, что имена свойств из обоих классов равны. Если они Арент вы должны modifiy они keyselectors ABIT так:

l1 => new { A=l1.Foo, B=l1.Bar}, 
l2 => new { A=l2.Herp, B=l2.Derp}, 
+1

Я сделал быстрый тест с моим методом и предложенным выше методом. Мой метод - 54 мс. предложил - 112 мс – Gokul

+1

@Gokul, который действительно зависит от количества элементов в этих списках. Если число мало, у объединения, вероятно, больше накладных расходов, создавая эти хеш-таблицы, прежде чем выполнять свою работу. Мой ответ также предполагал, что ваши списки содержат больше, чем несколько пунктов, иначе не было бы смысла просить более эффективное решение. – CSharpie

+0

mylist1 может содержать более 1000 - 10000 наименований. но mylist2 будет иметь 1- 10 пунктов. – Gokul

3

Вы также могли бы сделать присоединиться:

var query= from l in mylist1 
      join e in mylist2 on new {Property1=l.Property1,Property2=l.Property2} equals new {Property1=e.Property1,Property2=e.Property2} 
      select l; 
+0

Вы можете опустить «имена», что делает его более читаемым, я думаю. 'new {Property1 = l.Property1, Property2 = l.Property2}' => 'new {l.Property1, l.Property2}' – CSharpie

+0

Спасибо @CSharpie, я знаю об этом, но если имена свойства разные между этими двумя классами, тогда это необходимо сделать так. Я предполагаю, что это не настоящие имена, но если имена совпадут, да, имена свойств в анонимных типах могут быть опущены – octavioccl

+0

Вы правы, что делает ваш ответ более водонепроницаемым. – CSharpie