Как наиболее эффективно протестировать, если два массива содержат эквивалентные элементы в C # - PullRequest
10 голосов
/ 17 августа 2011

У меня есть два массива, и я хочу знать, содержат ли они одинаковые элементы. Equals(object obj) не работает, потому что массив является ссылочным типом. Я опубликовал свою попытку ниже, но, поскольку я уверен, что это обычная задача, я хотел бы знать, есть ли лучший тест.

    public bool ContainsEquivalentSequence<T>(T[] array1, T[] array2)
    {
        bool a1IsNullOrEmpty = ReferenceEquals(array1, null) || array1.Length == 0;
        bool a2IsNullOrEmpty = ReferenceEquals(array2, null) || array2.Length == 0;
        if (a1IsNullOrEmpty) return a2IsNullOrEmpty;
        if (a2IsNullOrEmpty || array1.Length != array2.Length) return false;
        for (int i = 0; i < array1.Length; i++)
            if (!Equals(array1[i], array2[i]))
                return false;
        return true;
    }

Обновление - System.Linq.Enumerable.SequenceEqual не лучше

Я отразил источник, и он не сравнивает длину до выполнения цикла . Это имеет смысл, поскольку метод обычно предназначен для IEnumerable<T>, а не для T[].

    public static bool SequenceEqual<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
    {
        if (comparer == null)
        {
            comparer = EqualityComparer<TSource>.Default;
        }
        if (first == null)
        {
            throw Error.ArgumentNull("first");
        }
        if (second == null)
        {
            throw Error.ArgumentNull("second");
        }
        using (IEnumerator<TSource> enumerator = first.GetEnumerator())
        {
            using (IEnumerator<TSource> enumerator2 = second.GetEnumerator())
            {
                while (enumerator.MoveNext())
                {
                    if (!enumerator2.MoveNext() || !comparer.Equals(enumerator.Current, enumerator2.Current))
                    {
                        return false;
                    }
                }
                if (enumerator2.MoveNext())
                {
                    return false;
                }
            }
        }
        return true;
    }

1 Ответ

23 голосов
/ 17 августа 2011

Я провел несколько тестов, используя Any, Contains, All и SequenceEqual, затем я выбрал лучший 3.

Существуют разные результаты для разных входов ...

Два идентичных массива размера 100: SequenceEqual был быстрее

[     SequenceEqual: 00:00:00.027   ]*
[     ContainsEqSeq: 00:00:00.046   ]
[          Parallel: 00:00:00.281   ]

Два идентичных массива размера 1000: SequenceEqual был быстрее

[     SequenceEqual: 00:00:00.240   ]*
[     ContainsEqSeq: 00:00:00.361   ]
[          Parallel: 00:00:00.491   ]

Два идентичных массива размером 10000: Parallel был быстрее

[     SequenceEqual: 00:00:02.357   ]
[     ContainsEqSeq: 00:00:03.341   ]
[          Parallel: 00:00:01.688   ]*

Два идентичных массива размером 50000: Parallel Ударная задница

[     SequenceEqual: 00:00:11.824   ]
[     ContainsEqSeq: 00:00:17.206   ]
[          Parallel: 00:00:06.811   ]*

Два массива с одним отличием в позиции 200: SequenceEqual был быстрее

[     SequenceEqual: 00:00:00.050   ]*
[     ContainsEqSeq: 00:00:00.075   ]
[          Parallel: 00:00:00.332   ]

Два массива с одним отличием в позиции 0: ContainsEqSeq и SequenceEqual были быстрее

[     SequenceEqual: 00:00:00.002   ]*
[     ContainsEqSeq: 00:00:00.001   ]*
[          Parallel: 00:00:00.211   ]

Два массива с одним отличием в позиции 999: SequenceEqual был быстрее

[     SequenceEqual: 00:00:00.237   ]*
[     ContainsEqSeq: 00:00:00.330   ]
[          Parallel: 00:00:00.691   ]

Два массива с одним отличием в позиции 9999: Parallel Удар в зад

[     SequenceEqual: 00:00:02.386   ]
[     ContainsEqSeq: 00:00:03.417   ]
[          Parallel: 00:00:01.614   ]*

Код SequenceEqual -

a1.SequenceEqual(a2)

Код для ContainsEqSeq - ваш метод.

Код Parallel -

bool a1IsNullOrEmpty = ReferenceEquals(a1, null) || a1.Length == 0;
bool a2IsNullOrEmpty = ReferenceEquals(a2, null) || a2.Length == 0;
if (a1IsNullOrEmpty) return a2IsNullOrEmpty;
if (a2IsNullOrEmpty || a1.Length != a2.Length) return false;

var areEqual = true;
Parallel.ForEach(a1,
    (i, s, x) =>
    {
        if (a1[x] != a2[x])
        {
            areEqual = false;
            s.Stop();
        }
    });

return areEqual;

Я бы сказал, что лучший вариант зависит от того, что вы будете вводить.

Если вы будете работать с огромными массивами (например, 10000+), я бы сказал, Parallel - лучший выбор, он проигрывает только тогда, когда есть разница в начале.

Для других случаев SequenceEqual может быть лучшим, я тестировал только с int[], но я считаю, что он может быть быстрым и для сложных типов.

Но помните, результаты будут отличаться в зависимости от ввода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...