C#泛型列表联合问题

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/849545/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 04:06:46  来源:igfitidea点击:

C# Generic List Union Question

c#linqgenerics

提问by Ganesha

I'm trying to merge 2 lists using "Union" so I get rid of duplicates. Following is the sample code:

我正在尝试使用“联合”合并 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();

Now the question is can I use Union and still get the record which has the latest date (using SomeDate property). The record itself can either be in tempList1 or tempList2.

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

Thanks in advance

提前致谢

采纳答案by Noldorin

The operation that is really suited to this purpose is an full outer join. The Enumerableclass has an implementation of inner join, which you can use to find the duplicates and select whichever you prefer.

真正适合此目的的操作是完全外连接。该Enumerable班有内实现连接,你可以用它来寻找重复的,并选择你喜欢哪个。

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

keySelectoris simply a function (could be a lambda expression) that extracts a key from an object of type SomeDetail. Now, to implement the full outer join, try something like this:

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

equalityComparershould be an object that implements IEqualityComparer<SomeDetail>and effectively uses the keyComparerfunction for testing equality.

equalityComparer应该是一个实现IEqualityComparer<SomeDetail>并有效使用keyComparer测试相等函数的对象。

Let me know if that does the job for you.

让我知道这是否适合您。

回答by John Weldon

You'd have to be able to tell Union how to pick which one of the duplicates to use. I don't know of a way to do that other than writing your own Union.

您必须能够告诉 Union 如何选择要使用的副本之一。除了编写自己的 Union 之外,我不知道还有什么方法可以做到这一点。

回答by Daniel Brückner

You cannot with the standard Unionmethod, but you can create an extension method Unionfor List<SomeDetail>with this special handling and this method will be used because the signature fits better.

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

回答by Chris Doggett

Why not just use HashSet<T>?

为什么不直接使用 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();

回答by Michael D. Irizarry

Merge generic lists

合并通用列表

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

回答by Adem Aygun

try this:

尝试这个:

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