2009-05-11 3 views
8

Я пытаюсь объединить 2 списка, используя «Союз», поэтому я избавляюсь от дубликатов. Ниже приведен пример кода:C# Общий список вопросов союза

public class SomeDetail 
{ 
    public string SomeValue1 { get; set; } 
    public string SomeValue2 { get; set; } 
    public string SomeDate { get; set; } 
} 

public class SomeDetailComparer : IEqualityComparer<SomeDetail> 
{ 
    bool IEqualityComparer<SomeDetail>.Equals(SomeDetail x, SomeDetail y) 
    { 
     // Check whether the compared objects reference the same data.   
     if (Object.ReferenceEquals(x, y)) 
      return true; 
     // Check whether any of the compared objects is null.   
     if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null)) 
      return false; 
     return x.SomeValue1 == y.SomeValue1 && x.SomeValue2 == y.SomeValue2; 
    } 
    int IEqualityComparer<SomeDetail>.GetHashCode(SomeDetail obj) 
    { 
     return obj.SomeValue1.GetHashCode(); 
    } 
} 

List<SomeDetail> tempList1 = new List<SomeDetail>(); 
List<SomeDetail> tempList2 = new List<SomeDetail>(); 

List<SomeDetail> detailList = tempList1.Union(tempList2, SomeDetailComparer).ToList(); 

Теперь вопрос можно ли использовать Союз и до сих пор получить запись, которая имеет самую последнюю дату (с использованием SomeDate собственности). Сама запись может быть либо в tempList1, либо в tempList2.

Заранее спасибо

ответ

8

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

var duplicates = Enumerable.Join(tempList1, tempList2, keySelector, keySelector, 
    (item1, item2) => (item1.SomeDate > item2.SomeDate) ? item1 : item2) 
    .ToList(); 

keySelector это просто функция (может быть лямбда-выражение), который извлекает ключ из объекта типа SomeDetail. Теперь, чтобы реализовать полное внешнее соединение, попробовать что-то вроде этого:

var keyComparer = (SomeDetail item) => new { Value1 = item.SomeValue1, 
    Value2 = item.SomeDetail2 }; 
var detailList = Enumerable.Union(tempList1.Except(tempList2, equalityComparer), 
    tempList2.Except(tempList1, equalityComparer)).Union(
    Enumerable.Join(tempList1, tempList2, keyComparer, keyComparer 
    (item1, item2) => (item1.SomeDate > item2.SomeDate) ? item1 : item2)) 
    .ToList(); 

equalityComparer должен быть объект, который реализует IEqualityComparer<SomeDetail> и эффективно использует keyComparer функцию для проверки равенства.

Сообщите мне, если это сработает для вас.

+0

Я использовал уникальное значение в классе SomeDetail для селектора, но не returing никаких записей. Любая помощь Пожалуйста? вар detailList = Enumerable.Join (tempList1, tempList2, элемент1 => item1.UniqueKey, элемент2 => item2.UniqueKey, (элемент1, элемент2) => (item1.SomeDate> item2.SomeDate) элемент1: элемент2) .ToList(); – Ganesha

+0

@ Ganesha: Вы подтвердили, что есть * по крайней мере некоторые предметы с одинаковыми значениями UniqueKey? – Noldorin

+0

О! Списки могут иметь совершенно разные значения. Если есть соответствующее значение, тогда необходимо принять во внимание дату, чтобы решить, какой из них будет выбран. Если нет соответствующего значения, значение все равно придется копировать. (как и в случае Союза) – Ganesha

1

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

1

Вы не можете со стандартным Union метода, но вы можете создать метод Union расширения для List<SomeDetail> с этой специальной обработкой, и этот метод будет использоваться, поскольку подпись лучше подходит.

1

Почему бы не просто использовать HashSet <T>?

List<SomeDetail> tempList1 = new List<SomeDetail>(); 
List<SomeDetail> tempList2 = new List<SomeDetail>(); 

HashSet<SomeDetail> hs = new HashSet<SomeDetail>(new SomeDetailComparer()); 

hs.UnionWith(tempList1); 
hs.UnionWith(tempList2); 

List<SomeDetail> detailList = hs.ToList(); 
+0

Это будет работать, если мне нужны уникальные записи. У меня есть дополнительное требование, когда при слиянии мне нужна запись с последней датой между двумя списками. – Ganesha

0

Объединить общие списки

public static List<T> MergeListCollections<T>(List<T> firstList, List<T> secondList) 
    { 
     List<T> merged = new List<T>(firstList); 
     merged.AddRange(secondList); 
     return merged; 
    } 
+0

Я не думаю, что это устранит дубликаты, которые были указаны в вопросе. – AaronLS

-1

попробовать это:

list1.RemoveAll(p => list2.Any(z => z.SomeValue1 == p.SomeValue1 && 
           z => z.SomeValue2 == p.SomeValue1 && 
           z => z.SomeDate == p.SomeDate)); 
var list3 = list2.Concat<SomeDetail>(list1).ToList();