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
C# Generic List Union Question
提问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 Enumerable
class 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();
keySelector
is 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();
equalityComparer
should be an object that implements IEqualityComparer<SomeDetail>
and effectively uses the keyComparer
function 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 Union
method, but you can create an extension method Union
for List<SomeDetail>
with this special handling and this method will be used because the signature fits better.
您不能使用标准Union
方法,但您可以使用此特殊处理创建扩展方法Union
,List<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();