寻找需要对日期字段进行排序的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也标题作者通常不会考虑使用说2位数,当他们的编号方案超过9.例如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, ....
如果我有Levenshtein函数StringDistance(s1,s2),我将如何适应LINQ查询:)
答案 0 :(得分:0)
按日期排序,您应使用OrderBy运算符。
示例:
//Assuming your table is called Table in datacontext ctx
var data = from t in ctx.Table
order by t.Date
select t;
对于在相似之后对字符串进行分组,您应该考虑类似Hamming distance或Metaphone算法的内容。 (虽然我不知道在.Net中直接实现这些。)
编辑:正如svick的评论中所建议的那样,Levenstein distance也可以被认为是汉明距离的更好替代方案。
答案 1 :(得分:0)
假设您的Title和Date字段包含在名为model的类中,请考虑以下类定义 公共类模型
{
public DateTime Date{get;set;}
public string Title{get;set;}
public string Prefix
{get
{
return Title.Substring(0,Title.LastIndexOf(' '));
}
}
}
除了Date和Title属性之外,我创建了一个没有setter的前缀属性,它使用substring返回公共前缀。您可以在此属性的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);
}
编辑&gt;&gt;&gt; 如果我们把前缀放在一边,那么查询本身就不会返回我之后的内容: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);
答案 2 :(得分:0)
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))