Проверьте, равны ли два списка
У меня есть класс следующим образом:
public class Tag {
public Int32 Id { get; set; }
public String Name { get; set; }
}
И у меня есть два списка тегов:
List<Tag> tags1;
List<Tag> tags2;
Я использовал LINQ, чтобы получить идентификаторы каждого списка тэгов. И затем:
List<Int32> ids1 = new List<Int32> { 1, 2, 3, 4 };
List<Int32> ids2 = new List<Int32> { 1, 2, 3, 4 };
List<Int32> ids3 = new List<Int32> { 2, 1, 3, 4 };
List<Int32> ids4 = new List<Int32> { 1, 2, 3, 5 };
List<Int32> ids5 = new List<Int32> { 1, 1, 3, 4 };
ids1 должно быть равно ids2 и ids3... Оба имеют одинаковые числа.
ids1 не должен быть равным ids4 и ids5...
Я попробовал следующее:
var a = ints1.Equals(ints2);
var b = ints1.Equals(ints3);
Но оба дают мне ложь.
Каков самый быстрый способ проверить, совпадают ли списки тегов?
UPDATE
Я ищу POSTS, которые TAGS точно такие же, как TAGS в книге.
IRepository repository = new Repository(new Context());
IList<Tags> tags = new List<Tag> { new Tag { Id = 1 }, new Tag { Id = 2 } };
Book book = new Book { Tags = new List<Tag> { new Tag { Id = 1 }, new Tag { Id = 2 } } };
var posts = repository
.Include<Post>(x => x.Tags)
.Where(x => new HashSet<Int32>(tags.Select(y => y.Id)).SetEquals(book.Tags.Select(y => y.Id)))
.ToList();
Я использую Entity Framework, и я получаю сообщение об ошибке:
Исключение типа "System.NotSupportedException" произошло в mscorlib.dll, но не было обработано в коде пользователя
Дополнительная информация: LINQ to Entities не распознает метод 'Boolean SetEquals (System.Collections.Generic.IEnumerable`1 [System.Int32])', и этот метод не может быть переведен в выражение хранилища.
Как это решить?
Ответы
Ответ 1
Используйте SequenceEqual
, чтобы проверить равенство последовательности, потому что метод Equals
проверяет ссылочное равенство.
var a = ints1.SequenceEqual(ints2);
Или, если вам не нужен порядок элементов, используйте метод Enumerable.All
:
var a = ints1.All(ints2.Contains);
Вторая версия также требует другой проверки для Count
, потому что она вернет true, даже если ints2
содержит больше элементов, чем ints1
. Поэтому более правильная версия будет примерно такой:
var a = ints1.All(ints2.Contains) && ints1.Count == ints2.Count;
Чтобы проверить неравенство, просто отмените результат метода All
:
var a = !ints1.All(ints5.Contains)
Ответ 2
List<T>
равенство не проверяет их поэтапно. Вы можете использовать метод LINQ SequenceEqual
для этого:
var a = ints1.SequenceEqual(ints2);
Чтобы игнорировать порядок, используйте SetEquals
:
var a = new HashSet<int>(ints1).SetEquals(ints2);
Это должно работать, потому что вы сравниваете последовательности идентификаторов, которые не содержат дубликатов. Если это так, и вам нужно учитывать дубликаты, способ сделать это в линейном времени состоит в том, чтобы составить хеш-словарь для подсчета, добавить один для каждого элемента первой последовательности, вычесть его для каждого элемента второго последовательность и проверить, являются ли результирующие подсчеты нулями:
var counts = ints1
.GroupBy(v => v)
.ToDictionary(g => g.Key, g => g.Count());
var ok = true;
foreach (var n in ints2) {
int c;
if (counts.TryGetValue(n, out c)) {
counts[n] = c-1;
} else {
ok = false;
break;
}
}
var res = ok && counts.Values.All(c => c == 0);
Наконец, если вы в порядке с решением O(N*LogN)
, вы можете отсортировать две последовательности и сравнить их для равенства с помощью SequenceEqual
.
Ответ 3
Enumerable.SequenceEqual(FirstList.OrderBy(fElement => fElement),
SecondList.OrderBy(sElement => sElement))