查找相等的字符串集及其计数(不同的列表)
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() });
我正在尝试查找不同的集合及其数量。
假设您有以下模型。
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() });