C#通用列表联盟问题

时间:2009-05-11 19:03:25

标签: c# linq generics

我正在尝试使用“联盟”合并2个列表,因此我摆脱了重复。以下是示例代码:

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();

现在问题是我可以使用Union并仍然获取具有最新日期的记录(使用SomeDate属性)。记录本身可以在tempList1或tempList2中。

提前致谢

6 个答案:

答案 0 :(得分:8)

真正适合此目的的操作是full outer joinEnumerable类具有内部联接的实现,您可以使用它来查找重复项并选择您喜欢的任何内容。

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

keySelector只是一个函数(可以是lambda表达式),它从类型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函数来测试相等性。

请告诉我这是否适合您。

答案 1 :(得分:1)

您必须能够告诉Union如何选择要使用的副本中的哪一个。除了编写自己的联盟​​之外,我不知道如何做到这一点。

答案 2 :(得分:1)

您不能使用标准Union方法,但可以使用此特殊处理为Union创建扩展方法List<SomeDetail>,并且将使用此方法,因为签名更适合。< / p>

答案 3 :(得分:1)

为什么不直接使用HashSet&lt; T&gt;?

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();

答案 4 :(得分: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;
    }

答案 5 :(得分:-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();