C# .NET检查是否有两个IEnumerable<;T>;有相同的元素
可能重复:C# .NET检查是否有两个IEnumerable<;T>;有相同的元素,c#,.net,linq,list,set,C#,.net,Linq,List,Set,可能重复: 我需要验证两个IEnumerable列表是否具有相同的元素,但顺序不一定相同 我的目标是.NET3.5 以下是测试。问题是,应该如何实现HasSameElements() var l1 = new[]{1,2,3}; var l2 = new[]{3,1,2}; bool rez1 = l1.HasSameElements(l2);//should be true var l3 = new[]{1,2,3,2}; var l4 = new[]{3,1,2,2}; bool re
我需要验证两个
IEnumerable
列表是否具有相同的元素,但顺序不一定相同
我的目标是.NET3.5
以下是测试。问题是,应该如何实现HasSameElements()
var l1 = new[]{1,2,3};
var l2 = new[]{3,1,2};
bool rez1 = l1.HasSameElements(l2);//should be true
var l3 = new[]{1,2,3,2};
var l4 = new[]{3,1,2,2};
bool rez2 = l3.HasSameElements(l4);//should be true
var l5 = new[]{1,2,3,2};
var l6 = new[]{1,2,3};
bool rez3 = l5.HasSameElements(l6);//should be false
传统注释:
- 在示例中,我使用的是IEnumerable,但T可以是任何东西。是否不一定要实现
i可比较
- Enumerable.SequenceEquals()本身不起作用,它要求元素的顺序相同
- 下面是一个用于
的模板:HasElements
public static class Extensions {
public static bool HasElements(this IEnumerable<T> l1, IEnumerable<T> l2){
throw new NotImplementedException();
}
}
公共静态类扩展{
公共静态布尔元素(此IEnumerable l1、IEnumerable l2){
抛出新的NotImplementedException();
}
}
使用:
您还可以传递自定义比较器
public static class Extensions
{
public static bool HasElements(
this IEnumerable<T> l1,
IEnumerable<T> l2,
IEqualityComparer<T> comparaer)
{
l2.Count() == l1.Count() &&
return l1.Intersect(l2, comparer).Count() == l2.Count();
}
}
公共静态类扩展
{
公共静态布尔元素(
这是可数l1,
IEnumerable l2,
IEqualityComparer(比较者)
{
l2.Count()==l1.Count()&&
返回l1.Intersect(l2,比较器).Count()==l2.Count();
}
}
尽管Cristi的基于的方法比基于
的方法要好得多,但您可能会侥幸逃脱:
source.Sort().SequenceEqual(target.Sort());
如果是单元测试,我不会担心性能。当然,您需要确保您的排序是稳定的。我会这样做
public static bool HasSameElements<T>(this IEnumerable<T> source, IEnumerable<T> target)
{
return (source.Count() == target.Count() && source.All(a => target.Contains(a)));
}
publicstaticboolhasamelements(此IEnumerable源,IEnumerable目标)
{
返回(source.Count()==target.Count()&&source.All(a=>target.Contains(a));
}
因为输入可以包含重复项,您只能使用。一种算法是:
if the lists contain a different number of elements return false
make a copy of listA
foreach element in listB
if the element exists in copyA remove the first match from copyA
otherwise return false
对于实现,您可以查看in-FluentAssert的逻辑。只需构建一个字典,将每个对象映射到它在序列中出现的次数,然后检查生成的字典是否相等 在这里:
静态类EnumerableExtensions{
公共静态bool hasamelementsas(
这是第一次,
数秒
) {
var firstMap=first
.GroupBy(x=>x)
.ToDictionary(x=>x.Key,x=>x.Count());
var secondMap=second
.GroupBy(x=>x)
.ToDictionary(x=>x.Key,x=>x.Count());
返回
firstMap.Keys.All(x=>
secondMap.Keys.Contains(x)&&firstMap[x]==secondMap[x]
) &&
secondMap.Keys.All(x=>
firstMap.Keys.Contains(x)&&secondMap[x]==firstMap[x]
);
}
}
显然,重复的代码可以重构为助手方法,但这只会混淆这里的想法。对于
GroupBy
操作,您可以选择接受IEqualityComparer
。另外,您应该通过添加null
guards和其他什么来生成代码。取决于哪个是较大的集合…将不起作用。可枚举。Intersect返回一个集合。new[]{2,2}.Intersect(new[]{2,2})返回{2}刚开始只是检查计数是否等于,这很容易。如果可以的话,你真的想避免遍历序列两次。@Mitch:把这个注释作为一个答案,我会接受的。问题是重复的,但更好的答案是:,如果包含的对象是可排序的…这平均是O(n log n)
。我认为我的方法()是O(n)
。如果可以的话,你真的希望避免遍历序列两次。GroupBy()有O(n)复杂度吗?@Cristi Diaconescu:是的,应该是O(n)
。
if the lists contain a different number of elements return false
make a copy of listA
foreach element in listB
if the element exists in copyA remove the first match from copyA
otherwise return false
static class EnumerableExtensions {
public static bool HasSameElementsAs<T>(
this IEnumerable<T> first,
IEnumerable<T> second
) {
var firstMap = first
.GroupBy(x => x)
.ToDictionary(x => x.Key, x => x.Count());
var secondMap = second
.GroupBy(x => x)
.ToDictionary(x => x.Key, x => x.Count());
return
firstMap.Keys.All(x =>
secondMap.Keys.Contains(x) && firstMap[x] == secondMap[x]
) &&
secondMap.Keys.All(x =>
firstMap.Keys.Contains(x) && secondMap[x] == firstMap[x]
);
}
}