近10年来(Selman的回答)被接受的答案根本不起作用。你可以自己尝试一下:{2, 2, 3}和{2, 3, 3},Selman算法说它们相等。我同意一开始并不明显。
第二个得票最多的答案(Sergey的答案)包含了一些评论,建议了一个非常快速的算法。我进行了一次小型基准测试(代码在底部)。我包括了3个答案(Selman、Sergey、Pankaj)。我还添加了2个新算法(Guru和EricO)。根据我的基准测试,Sergey的算法与其他一些算法相比并不是很快。我知道速度本身并不是问题的标准,但答案提出了一个非常高效的算法。
在这里,我包括了一个小型基准测试来比较提出的解决方案以及其他2个解决方案。虽然远非完美和全面,但这个基准测试可以给出一个关于有效性和性能的好主意。我建议在选择要在自己的代码中实现的内容之前,先检查一下结果。
测试代码和比较函数的实现在结果下方。感谢Guru对算法的反馈和好的想法(我认为它值得成为一个独立的答案;-))。
结果:
Start Compare for Int32 of size: 3
CompareEnumerableAnyOrderSelman : 00:00:00.0006856. Equal: True <<<<< ERROR
CompareEnumerableAnyOrderSergey : 00:00:00.0045392. Equal: False
CompareEnumerableAnyOrderPankaj : 00:00:00.0019844. Equal: False
CompareEnumerableAnyOrderGuru : 00:00:00.0002651. Equal: False
CompareEnumerableAnyOrderEricO : 00:00:00.0005945. Equal: False
End Compare
Start Compare for Int32 of size: 10000000
CompareEnumerableAnyOrderSergey : 00:00:11.6260563. Equal: True
CompareEnumerableAnyOrderPankaj : 00:00:03.2376179. Equal: True
CompareEnumerableAnyOrderGuru : 00:00:01.0078811. Equal: True
CompareEnumerableAnyOrderEricO : 00:00:01.5709527. Equal: True
End Compare
Start Compare for Int32 of size: 10000000
CompareEnumerableAnyOrderSergey : 00:00:12.9824722. Equal: False
CompareEnumerableAnyOrderPankaj : 00:00:03.8619141. Equal: False
CompareEnumerableAnyOrderGuru : 00:00:01.0829506. Equal: False
CompareEnumerableAnyOrderEricO : 00:00:02.0760940. Equal: False
End Compare
Start Compare for String of size: 10000000
CompareEnumerableAnyOrderSergey : 00:00:16.3923001. Equal: True
CompareEnumerableAnyOrderPankaj : 00:00:54.0820172. Equal: True
CompareEnumerableAnyOrderGuru : 00:00:53.5317528. Equal: True
CompareEnumerableAnyOrderEricO : 00:00:05.9972781. Equal: True
End Compare
Start Compare for String of size: 10000000
CompareEnumerableAnyOrderSergey : 00:00:14.3085444. Equal: False
CompareEnumerableAnyOrderPankaj : 00:00:54.4835349. Equal: False
CompareEnumerableAnyOrderGuru : 00:00:53.6763668. Equal: False
CompareEnumerableAnyOrderEricO : 00:00:05.6920709. Equal: False
End Compare
Start Compare for Int32 of size: 1000000
CompareEnumerableAnyOrderSergey : 00:00:00.7707951. Equal: True
CompareEnumerableAnyOrderPankaj : 00:00:00.2131278. Equal: True
CompareEnumerableAnyOrderGuru : 00:00:00.0892336. Equal: True
CompareEnumerableAnyOrderEricO : 00:00:00.5455456. Equal: True
End Compare
Start Compare for Int32 of size: 1000000
CompareEnumerableAnyOrderSergey : 00:00:00.5982986. Equal: False
CompareEnumerableAnyOrderPankaj : 00:00:00.2248797. Equal: False
CompareEnumerableAnyOrderGuru : 00:00:00.0937744. Equal: False
CompareEnumerableAnyOrderEricO : 00:00:00.1462340. Equal: False
End Compare
Start Compare for String of size: 1000000
CompareEnumerableAnyOrderSergey : 00:00:01.3971059. Equal: True
CompareEnumerableAnyOrderPankaj : 00:00:04.3682767. Equal: True
CompareEnumerableAnyOrderGuru : 00:00:03.7275648. Equal: True
CompareEnumerableAnyOrderEricO : 00:00:00.4822032. Equal: True
End Compare
Start Compare for String of size: 1000000
CompareEnumerableAnyOrderSergey : 00:00:01.1479243. Equal: False
CompareEnumerableAnyOrderPankaj : 00:00:04.2601652. Equal: False
CompareEnumerableAnyOrderGuru : 00:00:03.7690159. Equal: False
CompareEnumerableAnyOrderEricO : 00:00:00.2350588. Equal: False
End Compare
Start Compare for Int32 of size: 100000
CompareEnumerableAnyOrderSergey : 00:00:00.1446754. Equal: True
CompareEnumerableAnyOrderPankaj : 00:00:00.0212269. Equal: True
CompareEnumerableAnyOrderGuru : 00:00:00.0087268. Equal: True
CompareEnumerableAnyOrderEricO : 00:00:00.0081945. Equal: True
End Compare
Start Compare for Int32 of size: 100000
CompareEnumerableAnyOrderSergey : 00:00:00.0245328. Equal: False
CompareEnumerableAnyOrderPankaj : 00:00:00.0232001. Equal: False
CompareEnumerableAnyOrderGuru : 00:00:00.0075184. Equal: False
CompareEnumerableAnyOrderEricO : 00:00:00.0139519. Equal: False
End Compare
Start Compare for String of size: 100000
CompareEnumerableAnyOrderSergey : 00:00:00.0808056. Equal: True
CompareEnumerableAnyOrderPankaj : 00:00:00.2401923. Equal: True
CompareEnumerableAnyOrderGuru : 00:00:00.1936675. Equal: True
CompareEnumerableAnyOrderEricO : 00:00:00.0392954. Equal: True
End Compare
Start Compare for String of size: 100000
CompareEnumerableAnyOrderSergey : 00:00:00.1257959. Equal: False
CompareEnumerableAnyOrderPankaj : 00:00:00.2398588. Equal: False
CompareEnumerableAnyOrderGuru : 00:00:00.2811503. Equal: False
CompareEnumerableAnyOrderEricO : 00:00:00.0406129. Equal: False
End Compare
测试代码:
using System.Diagnostics;
using System.Text;
using General.Compare;
namespace ConsoleAppTestEnumCompare
{
internal class Program
{
static void Main(string[] args)
{
int[] itemsToShowStackOverflowAcceptedAnswerError = new int[] { 2, 2, 3 };
int[] itemsToShowStackOverflowAcceptedAnswerError2 = new int[] { 2, 3, 3 };
Test(itemsToShowStackOverflowAcceptedAnswerError, itemsToShowStackOverflowAcceptedAnswerError2);
foreach (var countOfInt in new int[] { 100000000, 10000000, 1000000, 100000 })
{
Random rnd = new Random();
List<int> list1 = new List<int>();
for (int i = 0; i < countOfInt; i++)
{
list1.Add(rnd.Next(list1.Count));
}
List<int> list2 = new List<int>(list1);
list2.Sort();
Test(list1, list2);
list1[list1.Count / 2] = list1[list1.Count / 2] + 1;
Test(list1, list2);
List<string> listString1 = new List<string>();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < countOfInt; i++)
{
sb.Clear();
int stringSize = rnd.Next(1, 12);
for (int n = 0; n < stringSize; n++)
{
sb.Append((char)rnd.Next((int)'a', (int)'z'));
}
listString1.Add(sb.ToString());
}
List<string> listString2 = new List<string>(listString1);
listString2.Sort();
Test(listString1, listString2);
listString1[listString1.Count / 2] = listString1[listString1.Count / 2] + 1;
Test(listString1, listString2);
}
}
static void Test<T>(IEnumerable<T> list1, IEnumerable<T> list2)
{
(Func<IEnumerable<T>, IEnumerable<T>, bool> Compare, string Name)[] compareActions = new (Func<IEnumerable<T>, IEnumerable<T>, bool>, string)[5];
compareActions[0] = (CompareEnumerableExtension.CompareEnumerableAnyOrderSelman, nameof(CompareEnumerableExtension.CompareEnumerableAnyOrderSelman));
compareActions[1] = (CompareEnumerableExtension.CompareEnumerableAnyOrderSergey, nameof(CompareEnumerableExtension.CompareEnumerableAnyOrderSergey));
compareActions[2] = (CompareEnumerableExtension.CompareEnumerableAnyOrderPankaj, nameof(CompareEnumerableExtension.CompareEnumerableAnyOrderPankaj));
compareActions[3] = (CompareEnumerableExtension.CompareEnumerableAnyOrderGuru, nameof(CompareEnumerableExtension.CompareEnumerableAnyOrderGuru));
compareActions[4] = (CompareEnumerableExtension.CompareEnumerableAnyOrderEricO, nameof(CompareEnumerableExtension.CompareEnumerableAnyOrderEricO));
Debug.WriteLine($"Start Compare for {typeof(T).Name} of size: {list1.Count()}");
Console.WriteLine($"Start Compare for {typeof(T).Name} of size: {list1.Count()}");
bool areListsEqual;
Stopwatch stopwatch;
foreach(var compareAction in compareActions)
{
if (list1.Count() > 100 && compareAction.Name == nameof(CompareEnumerableExtension.CompareEnumerableAnyOrderSelman))
{
continue;
}
stopwatch = Stopwatch.StartNew();
areListsEqual = compareAction.Compare(list1, list2);
stopwatch.Stop();
Debug.WriteLine($"{compareAction.Name, -33} : {stopwatch.Elapsed}. Equal: {areListsEqual}");
Console.WriteLine($"{compareAction.Name, -33} : {stopwatch.Elapsed}. Equal: {areListsEqual}");
}
Debug.WriteLine("End Compare");
Console.WriteLine("End Compare");
Debug.WriteLine("");
Console.WriteLine();
}
}
}
比较功能:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace General.Compare
{
public static class CompareEnumerableExtension
{
public static bool CompareEnumerableInSameOrder<T>(this IEnumerable<T> enum1, IEnumerable<T> enum2)
{
return enum1.SequenceEqual(enum2);
}
public static bool CompareEnumerableAnyOrderPankaj<T>(this IEnumerable<T> enum1, IEnumerable<T> enum2)
{
return Enumerable.SequenceEqual(enum1.OrderBy(fElement => fElement), enum2.OrderBy(sElement => sElement));
}
public static bool CompareEnumerableAnyOrderSelman<T>(this IEnumerable<T> enum1, IEnumerable<T> enum2)
{
return enum1.Count() == enum2.Count() && enum1.All(enum2.Contains);
}
public static bool CompareEnumerableAnyOrderSergey<T>(this IEnumerable<T> enum1, IEnumerable<T> enum2)
{
var counts = enum1.GroupBy(v => v).ToDictionary(g => g.Key, g => g.Count());
var ok = true;
foreach (var n in enum2)
{
if (counts.TryGetValue(n, out int c))
{
counts[n] = c - 1;
}
else
{
ok = false;
break;
}
}
return ok && counts.Values.All(c => c == 0);
}
public static bool CompareEnumerableAnyOrderGuru<T>(this IEnumerable<T> enum1, IEnumerable<T> enum2)
{
var list1 = new List<T>(enum1);
list1.Sort();
var list2 = new List<T>(enum2);
list2.Sort();
return Enumerable.SequenceEqual(list1, list2);
}
public static bool CompareEnumerableAnyOrderEricO<T>(this IEnumerable<T> enum1, IEnumerable<T> enum2)
{
if (enum1.Count() != enum2.Count())
return false;
#pragma warning disable CS8714 // The type cannot be used as type parameter in the generic type or method. Nullability of type argument doesn't match 'notnull' constraint.
Dictionary<T, int> counts = new Dictionary<T, int>(enum1.Count());
#pragma warning restore CS8714 // The type cannot be used as type parameter in the generic type or method. Nullability of type argument doesn't match 'notnull' constraint.
int nullCount = 0;
foreach (var n in enum1)
{
if (n == null)
{
nullCount++;
continue;
}
if (counts.TryGetValue(n, out int c))
{
counts[n] = c + 1;
}
else
{
counts[n] = 1;
}
}
var ok = true;
foreach (var n in enum2)
{
if (n == null)
{
nullCount++;
continue;
}
if (counts.TryGetValue(n, out int c))
{
counts[n] = c - 1;
}
else
{
ok = false;
break;
}
}
return ok && nullCount == 0 && counts.Values.All(c => c == 0);
}
}
}
ids5
包含重复项。这是有意为之吗? - Sergey Kalinichenko[EF]
标签,并确保新问题的标题为“在EF的Where子句内部比较列表”或类似内容。 - Sergey Kalinichenko