2011-12-19 6 views
1

Предположим, что у меня есть два списка типа MyCustomType, класс, который может быть как это:Создать список из сравнения двух списков C#

public class MyCustomType{ 
    public int Classification {get; set;} 
    public string Title {get; set;} 
    public string Text {get; set;} 
} 

Я хочу создать третий список типов Tuple<MyCustomType,MyCustomType>, которые будет содержать какую-то «полное внешнее соединение» между ними, на основе условия (например, положить их вместе, если они получили такое же название и классификация)

Пример:

list1: 
Classification  Title  Text 
Movie    300  bla 
Game    Star Wars the dark side are they 

list2: 
Movie    300  updated bla 
TV Show    CSI  cool 

Полученный результат будет

list3: 
MyCustomType            MyCustomType 
Movie    300  bla      Movie    300  updated bla 
Game    Star Wars the dark side are they (null) 
(null)             TV Show    CSI  cool 

Они будут соответствовать детали классификации и название, и поставить нуль на другой стороне, когда один не соответствует.

Как я могу это сделать (возможно, с помощью LINQ?)

Я занимаюсь разработкой в ​​C#, .NET 4.0.

Я хочу это для моего экспериментального проекта для C#, «семантического» инструмента слияния C# с использованием Roslyn. Я хочу сравнить и сопоставить SyntaxNodes по типу и имени.

ответ

2

Внешние соединения не поддерживаются в Linq. Но вы можете сделать левое соединение и право присоединиться, а затем положить их вместе:

var left = 
    from x in list1 
    join y in list2 
     on new { x.Title, x.Classification } 
     equals { y.Title, y.Classification } 
     into tmp 
    from y in tmp.DefaultIfEmpty() 
    select Tuple.Create(x, y); 

var right = 
    from y in list2 
    join x in list1 
     on new { y.Title, y.Classification } 
     equals { x.Title, x.Classification } 
     into tmp 
    from y in tmp.DefaultIfEmpty() 
    where x == null // already included in left 
    select Tuple.Create(x, y); 

var result = left.Concat(right); 

EDIT: если вы хотите, наружный не-эквисоединения, вы можете сделать что-то подобное:

var left = 
    from x in list1 
    from y in list2.Where(y2 => MatchSyntaxNode(x, y2)).DefaultIfEmpty() 
    select Tuple.Create(x, y); 

var right = 
    from y in list2 
    from x in list1.Where(x2 => MatchSyntaxNode(x2, y)).DefaultIfEmpty() 
    where x == null // already included in left 
    select Tuple.Create(x, y); 

var result = left.Concat(right); 

(непроверенные)

+0

Можно ли использовать соединение с предикатом? поэтому я мог бы написать что-то вроде 'join y в списке2 в MatchSyntaxNode (x, y)'? –

+0

@ConradClark, см. Мой обновленный ответ –

+0

Во втором объявлении (var right) вместо 'join' я должен положить' from', правильно? И спасибо, это сработало. Я отмечаю как ответ. –

2

Вы можете попробовать это:

firstList.Select(x=>new Tuple<YourType,YourType>(x, secondList.FirstOrDefault(__yourcondition__))) 
     .Union(secondList.Any(!firstList.Any(__yourcondition__)) 
     .Select(x=>new Tuple<YourType,YourType>(null, x)); 

«Левое соединение», соединенное с правым соединением.

+0

Ваше решение отлично работало, я + 1 его, так как я могу отметить только один ответ. –

+0

Только что узнал, у вас тоже хорошая производительность. –

Смежные вопросы