我有这样一门课:

public class Tag {
    public Int32 Id { get; set; }
    public String Name { get; set; }
}

我有两个标签列表:

List<Tag> tags1;
List<Tag> tags2;

我使用LINQ的select来获取每个标记列表的id。然后:

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);

但两者都给我虚假。

检查标签列表是否相等的最快方法是什么?

更新

我正在寻找标签与一本书中的标签完全相同的帖子。

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();

我使用实体框架,我得到的错误:

System类型的异常。在mscorlib.dll中出现NotSupportedException',但在用户代码中没有处理 附加信息:LINQ to Entities不识别方法'Boolean SetEquals(System.Collections.Generic.IEnumerable ' 1[System.Int32])'方法,并且该方法不能转换为存储表达式。

我怎么解决这个问题?


当前回答

List<T>等式不会逐个元素检查它们。你可以使用LINQ的SequenceEqual方法:

var a = ints1.SequenceEqual(ints2);

要忽略顺序,使用SetEquals:

var a = new HashSet<int>(ints1).SetEquals(ints2);

这应该可以工作,因为您正在比较id序列,其中不包含重复项。如果是这样,并且你需要考虑重复,那么在线性时间内的方法是组成一个基于哈希的计数字典,为第一个序列的每个元素添加一个,为第二个序列的每个元素减去一个,并检查结果计数是否全为零:

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比较它们是否相等。

其他回答

List<T>等式不会逐个元素检查它们。你可以使用LINQ的SequenceEqual方法:

var a = ints1.SequenceEqual(ints2);

要忽略顺序,使用SetEquals:

var a = new HashSet<int>(ints1).SetEquals(ints2);

这应该可以工作,因为您正在比较id序列,其中不包含重复项。如果是这样,并且你需要考虑重复,那么在线性时间内的方法是组成一个基于哈希的计数字典,为第一个序列的每个元素添加一个,为第二个序列的每个元素减去一个,并检查结果计数是否全为零:

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比较它们是否相等。

使用SequenceEqual检查序列是否相等,因为Equals方法检查引用是否相等。

var a = ints1.SequenceEqual(ints2);

如果不关心元素顺序,则使用Enumerable。所有的方法:

var a = ints1.All(ints2.Contains);

第二个版本还需要对Count进行另一次检查,因为即使ints2包含的元素比ints1多,它也会返回true。所以更正确的版本应该是这样的:

var a = ints1.All(ints2.Contains) && ints1.Count == ints2.Count;

为了检查不等式,只需反转All方法的结果:

var a = !ints1.All(ints2.Contains)
Enumerable.SequenceEqual(FirstList.OrderBy(fElement => fElement), 
                         SecondList.OrderBy(sElement => sElement))