查找相等的字符串集及其计数(不同的列表)

Find the equal sets of strings and their count (distinct lists)

我正在尝试查找不同的集合及其数量。

假设您有以下模型。

public class AModel {
   public IList<string> Tags { get; set; }
}

并且您有上述模型的列表,假设 AModel 的 50.000 个实例具有 1...N Tags.

我需要使用高性能 LINQ 找到不同的 Tags,列出而不是列表值(顺序无关紧要,计数和标记字符串很重要)。

示例:

List<AModel> models = new List<AModel>{
   new AModel { Tags = new List<string> { "Tag1", "Tag2" } },
   new AModel { Tags = new List<string> { "Tag2", "Tag1" } },
   new AModel { Tags = new List<string> { "Tag1", "Tag1" } },
   new AModel { Tags = new List<string> { "Tag2", "Tag2" } },
   new AModel { Tags = new List<string> { "Tag2", "Tag2" } },
};

所以,我需要一个结果:

List: { "Tag1", "Tag2" } Count: 2
List: { "Tag1", "Tag1" } Count: 1
List: { "Tag2", "Tag2" } Count: 2

到目前为止,我已经检查过 SetEquals 和 SequenceEquals。我可以迭代所有模型的所有标签,并保持计数和集合相等,如果我已经检查过,则传递下一个,但这是适得其反的。

我解决这个问题的方法是先对标签进行排序,然后将它们组合起来形成一个唯一的键,然后我可以使用该键进行分组。分组应该会自动为我提供密钥和计数。

这里有一个粗略的草稿可以帮助您入门:

foreach(var value in models.Select(model => String.Join(";", model.Tags.OrderBy(tags => tags))).GroupBy(list => list))
{
     Console.WriteLine(value.Key + "," + value.Count());
}

输出与您想要的非常相似:

标签 1;标签 2,2
标记 1;标记 1,1
Tag2;Tag2,2

实施 EqualityComparer<IList<string>>

public override bool Equals(IList<string> x, IList<string> y)
{
    return Enumerable.SequenceEqual(x.OrderBy(i => i), y.OrderBy(i => i));
}

public override int GetHashCode(IList<string> obj)
{
    return obj.Select(i => i.GetHashCode()).Average().GetHashCode();
}

在linq groupby中使用

List<AModel> models = new List<AModel>() {
    new AModel { Tags = new List<string> { "Tag1", "Tag2" } },
    new AModel { Tags = new List<string> { "Tag2", "Tag1" } },
    new AModel { Tags = new List<string> { "Tag1", "Tag1" } },
    new AModel { Tags = new List<string> { "Tag2", "Tag2" } },
    new AModel { Tags = new List<string> { "Tag2", "Tag2" } },
};

var result = models
    .GroupBy(i => i.Tags, new ListEqualityComparer())
    .Select(i => new { Tags = i.Key, Count = i.Count() });