Каков самый короткий способ сравнения, если два IEnumerable <T> имеют одинаковые элементы в С#?

Возможный дубликат:
Проверьте, являются ли два IEnumerable <T> имеют одинаковые значения с одинаковыми частотами

Я написал

ОБНОВЛЕНО - исправление:

static bool HaveSameItems<T>(this IEnumerable<T> self, IEnumerable<T> other)
{
    return ! 
    ( 
        other.Except(this).Any() ||
        this.Except(other).Any()
    );
}

Разве нет более короткого пути? Я знаю, что есть SequenceEqual, но порядок для меня не имеет значения.

Ответы

Ответ 1

Даже если заказ не имеет значения для вас, он не исключает SequenceEqual как жизнеспособный вариант.

var lst1 = new [] { 2,2,2,2 };
var lst2 = new [] { 2,3,4,5 };
var lst3 = new [] { 5,4,3,2 };

//your current function which will return true
//when you compare lst1 and lst2, even though
//lst1 is just a subset of lst2 and is not actually equal
//as mentioned by Wim Coenen
(lst1.Count() == lst2.Count() &&
        !lst1.Except(lst2).Any()); //incorrectly returns true

//this also only checks to see if one list is a subset of another
//also mentioned by Wim Coenen
lst1.Intersect(lst2).Any(); //incorrectly returns true

//So even if order doesn't matter, you can make it matter just for
//the equality check like so:
lst1.OrderBy(x => x).SequenceEqual(lst2.OrderBy(x => x)); //correctly returns false
lst3.OrderBy(x => x).SequenceEqual(lst2.OrderBy(x => x)); // correctly returns true

Ответ 2

Здесь O(n) решение, которое только проходит каждую последовательность один раз (на самом деле, возможно, он даже не может полностью пройти вторую последовательность, у нее есть возможности раннего завершения):

public static bool HaveSameItems<T>(IEnumerable<T> a, IEnumerable<T> b) {
    var dictionary = a.GroupBy(x => x).ToDictionary(g => g.Key, g => g.Count());
    foreach(var item in b) {
        int value;
        if (!dictionary.TryGetValue(item, out value)) {
            return false;
        }
        if (value == 0) {
            return false;
        }
        dictionary[item] -= 1;
    }
    return dictionary.All(x => x.Value == 0);
}

Одна из недостатков этого решения заключается в том, что он не собирается хорошо взаимодействовать с LINQ to SQL, EF, NHiberate и т.д.