按最近的日期排序,并对相似的标题进行聚类(分组)
本文关键字:聚类 分组 标题 日期 最近 排序 相似 | 更新日期: 2023-09-27 17:58:22
查找需要在日期字段上排序但也有相似标题的LINQ。考虑以下所需的排序:
Title Date
"Some Title 1/3" 2009/1/3 "note1: even this is old title 3/3 causes this group to be 1st"
"Some Title 2/3" 2011/1/31 "note2: dates may not be in sequence with titles"
"Some Title 3/3" 2011/1/1 "note3: this date is most recent between "groups" of titles
"Title XYZ 1of2" 2010/2/1
"Title XYz 2of2" 2010/2/21
我展示了不同后缀的标题。如果一张海报的标题用了下面这样的东西怎么办?
"1 LINQ Tutorial"
"2 LINQ Tutorial"
"3 LINQ Tutorial"
查询如何识别这些标题相似?你不必解决所有问题,非常感谢第一个例子的解决方案。
谢谢。
附录#1 20110605@svick还提到,当他们的编号方案超过9时,标题作者通常不会考虑使用2位数。例如01、02…10、11等。
我看到的典型模式往往是前缀或后缀,甚至隐藏在中
1/10 1-10 ...
(1/10) (2/10) ...
1 of 10 2 of 10
Part 1 Part 2 ...
你也指出了一个有效的模式:
xxxx Tutorial : first session, xxxx Tutorial : second session, ....
如果我有一个Levenstein函数StringDistance(s1,s2),我将如何适应LINQ查询:)
LINQ中的普通分组(和SQL中的分组,但这与这里无关)通过为集合中的每个元素选择一些键来工作。您没有这样的密钥,所以我不会使用LINQ,而是使用两个嵌套的foreach
es:
var groups = new List<List<Book>>();
foreach (var book in books)
{
bool found = false;
foreach (var g in groups)
{
if (sameGroup(book.Title, g[0].Title))
{
found = true;
g.Add(book);
break;
}
}
if (!found)
groups.Add(new List<Book> { book });
}
var result = groups.Select(g => g.OrderBy(b => b.Date).ToArray()).ToArray();
这会逐渐创建一个组列表。将每本书与每组的第一本书进行比较。如果匹配,则将其添加到组中。如果没有匹配的组,则书本将创建一个新组。最后,我们使用带点符号的LINQ对结果进行排序。
如果将书籍与一组中的每本书进行比较,而不仅仅是第一本,那将是更正确的。但是你可能不会得到完全正确的结果,所以我认为这个优化是值得的
这具有时间复杂性O(N²)
,所以如果你有数百万本书,它可能不是最好的解决方案。
编辑:要对组进行排序,请使用类似的东西
groups.OrderBy(g => g.Max(b => b.Date))
对于按日期排序,您应该使用OrderBy运算符。
示例:
//Assuming your table is called Table in datacontext ctx
var data = from t in ctx.Table
order by t.Date
select t;
对于在相似性之后对字符串进行分组,您应该考虑类似于Hamming距离或Metaphone算法的东西。(尽管我不知道这些在.Net中的任何直接实现).
编辑:正如svick在评论中所建议的,Levenstein距离也可以被认为是Hamming距离的更好替代方案。
假设Title和Date字段包含在类调用模型中,请考虑以下类定义公共类模型
{
public DateTime Date{get;set;}
public string Title{get;set;}
public string Prefix
{get
{
return Title.Substring(0,Title.LastIndexOf(' '));
}
}
}
除了Date和Title属性外,我还创建了一个没有setter的前缀属性,它使用子字符串向我们返回公共前缀。您可以在这个属性的getter中使用您选择的任何方法。剩下的工作很简单。考虑一下这个Linqpad程序
void Main()
{
var model = new List<Model>{new Model{Date = new DateTime(2011,1,3), Title = "Some Title 1/3"},
new Model{Date = new DateTime(2011,1,1), Title = "Some Title 2/3"},
new Model{Date = new DateTime(2011,1,1), Title = "Some Title 3/3"},
new Model{Date = new DateTime(2011,1,31), Title = "Title XYZ 1of2"},
new Model{Date = new DateTime(2011,1,31), Title = "Title XYZ 2of2"}};
var result = model.OrderBy(x => x.Date).GroupBy(x => x.Prefix);
Console.WriteLine(result);
}
编辑>>如果我们把前缀放在一边,那么查询本身不会返回我想要的内容,即:1)按组的最近日期排序2)在集群中按标题排序。尝试以下
var model = new List<Model>{
new Model{Date = new DateTime(2009,1,3), Title = "BTitle 1/3"},
new Model{Date = new DateTime(2011,1,31), Title = "BTitle 2/3"},
new Model{Date = new DateTime(2011,1,1), Title = "BTitle 3/3"},
new Model{Date = new DateTime(2011,1,31), Title = "ATitle XYZ 2of2"},
new Model{Date = new DateTime(2011,1,31), Title = "ATitle XYZ 1of2"}
};
var result = model.OrderBy(x => x.Date).GroupBy(x => x.Prefix);
Console.WriteLine(result);