按最近日期和群集(组)类似标题排序

时间:2011-06-05 14:26:23

标签: c# linq sorting lambda group-by

寻找需要对日期字段进行排序的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查询:)

3 个答案:

答案 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 distanceMetaphone算法的内容。 (虽然我不知道在.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))