Ваш метод сравнения двух списков по сути такой:
private static bool SequenceUnorderedEqual<T>(IEnumerable<T> source1,
IEnumerable<T> source2)
{
var list1 = source1.ToList();
var list2 = source2.ToList();
list1.Sort();
list2.Sort();
return list1.SequenceEqual(list2);
}
Использование словаря по крайней мере в десять раз быстрее, за счет того, что он немного сложнее.
private static bool SequenceUnorderedEqual<T>(IEnumerable<T> source1,
IEnumerable<T> source2)
{
var occurences = new Dictionary<T, int>();
// Populating the dictionary using source1
foreach (var item in source1)
{
int value;
if (!occurences.TryGetValue(item, out value))
{
value = 0;
}
occurences[item] = value + 1;
}
// Depopulating the dictionary using source2
foreach (var item in source2)
{
int value;
if (!occurences.TryGetValue(item, out value))
{
value = 0;
}
if (value <= 0) return false;
occurences[item] = value - 1;
}
// Now all counters should be reduced to zero
return occurences.Values.All(c => c == 0);
}
Обновление: ниже - еще более быстрая версия, использующая параллелизм.
private static bool SequenceUnorderedEqual<T>(IEnumerable<T> source1,
IEnumerable<T> source2)
{
var task1 = Task.Run(() => GetOccurences(source1));
var task2 = Task.Run(() => GetOccurences(source2));
Task.WaitAll(task1, task2);
var occurences1 = task1.Result;
var occurences2 = task2.Result;
if (occurences1.Count != occurences2.Count) return false;
var result = Parallel.ForEach(occurences1, (entry1, loopState) =>
{
var found2 = occurences2.TryGetValue(entry1.Key, out var value2);
if (!found2 || entry1.Value != value2) loopState.Stop();
});
return result.IsCompleted;
Dictionary<T, int> GetOccurences(IEnumerable<T> source)
{
var dic = new Dictionary<T, int>();
foreach (var item in source)
{
dic[item] = dic.TryGetValue(item, out int c) ? c + 1 : 1;
}
return dic;
}
}