LINQ: Определите, содержат ли две последовательности точно такие же элементы

Мне нужно определить, содержат ли два набора точно одинаковые элементы. Заказ не имеет значения.

Например, эти два массива следует считать равными:

IEnumerable<int> data = new []{ 3,5,6,9 };
IEnumerable<int> otherData = new []{ 6,5,9,3}

Один набор не может содержать никаких элементов, которые не находятся в другом.

Можно ли это сделать, используя встроенные операторы запросов? И что было бы самым эффективным способом его реализации, учитывая, что количество элементов может варьироваться от нескольких до сотен?

Ответ 1

Если вы хотите обрабатывать массивы как "наборы" и игнорировать порядок и дублирующиеся элементы, вы можете использовать метод HashSet<T>.SetEquals:

var isEqual = new HashSet<int>(first).SetEquals(second);

В противном случае наилучшим вариантом, вероятно, будет сортировка обеих последовательностей таким же образом и использование SequenceEqual для их сравнения.

Ответ 2

Я предлагаю сортировать оба и выполнять поэтапное сравнение.

data.OrderBy(x => x).SequenceEqual(otherData.OrderBy(x => x))

Я не уверен, насколько быстро реализована реализация OrderBy, но если это O (n log n), то, как и ожидалось, общий алгоритм будет O (n log n).

Для некоторых случаев данных вы можете улучшить это, используя пользовательскую реализацию OrderBy, которая, например, использует сортировку count для O (n + k), где k - размер диапазона, в котором значения лежат.

Ответ 3

Если у вас могут быть дубликаты (или если вы хотите решение, которое лучше подходит для более длинных списков), я бы попробовал что-то вроде этого:

static bool IsSame<T>(IEnumerable<T> set1, IEnumerable<T> set2)
{
    if (set1 == null && set2 == null)
        return true;
    if (set1 == null || set2 == null)
        return false;

    List<T> list1 = set1.ToList();
    List<T> list2 = set2.ToList();

    if (list1.Count != list2.Count)
        return false;

    list1.Sort();
    list2.Sort();

    return list1.SequenceEqual(list2);
}

ОБНОВЛЕНИЕ: вы, ребята, правы. Решение Except() ниже должно выглядеть как до пересечения улицы. И он имеет паршивый perf для более длинных списков. Игнорируйте это предложение ниже!: -)

Вот простой способ сделать это. Обратите внимание, что это предполагает, что списки не имеют дубликатов.

bool same = data.Except (otherData).Count() == 0;

Ответ 4

Я знаю, что это старый вопрос, но вот еще один способ сделать это

IEnumerable<int> data = new[] { 3, 5, 6, 9 };               
IEnumerable<int> otherData = new[] { 6, 5, 9, 3 };

data = data.OrderBy(d => d);
otherData = otherData.OrderBy(d => d);
data.Zip(otherData, (x, y) => Tuple.Create(x, y)).All(d => d.Item1 == d.Item2);

Ответ 5

  • Сначала проверьте длину. Если они разные, наборы отличаются.
  • вы можете сделать data.Intersect(otherData); и проверить, что длина идентична.
  • ИЛИ, упростить сортировку наборов и прокручивать их.

Ответ 6

Это должно помочь:

    IEnumerable<int> data = new []{ 3,5,6,9 };
    IEnumerable<int> otherData = new[] {6, 5, 9, 3};

    if(data.All(x => otherData.Contains(x)))
    {
        //Code Goes Here
    }

Ответ 7

Сначала проверьте, имеют ли оба набора данных одинаковое количество элементов и проверяют, представлены ли все элементы в одной коллекции в другой

        IEnumerable<int> data = new[] { 3, 5, 6, 9 };
        IEnumerable<int> otherData = new[] { 6, 5, 9, 3 };

        bool equals = data.Count() == otherData.Count() && data.All(x => otherData.Contains(x));