Сортировать по самой последней дате и кластеру (группе) похожих заголовков - PullRequest
2 голосов
/ 05 июня 2011

Поиск 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, ....

Если у меня есть функция Левенштейна StringDistance (s1, s2), как бы я вписался в запрос LINQ:)

Ответы [ 3 ]

0 голосов
/ 05 июня 2011

Предполагая, что ваши поля Title и Date содержатся в классе, называемом model, рассмотрим следующее общедоступное определение класса класса Model

{
    public DateTime Date{get;set;}
    public string Title{get;set;}
    public string Prefix
    {get
        {
            return Title.Substring(0,Title.LastIndexOf(' '));
        }
    }
}

Наряду со свойствами Date и Title я создал свойство префикса без установщика, и этовозвращая нам общий префикс с использованием подстроки.Вы можете использовать любой метод по вашему выбору в получателе этого свойства.Остальная работа проста.Рассмотрим эту программу 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);
0 голосов
/ 07 июня 2011

Обычная группировка в 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))
0 голосов
/ 05 июня 2011

Для заказа по дате вы должны использовать оператор OrderBy .

Пример:

//Assuming your table is called Table in datacontext ctx
var data = from t in ctx.Table
           order by t.Date
           select t;

Для группировки строк после сходства вы должны рассмотреть что-то вроде расстояния Хэмминга или Метафон . (Хотя я не знаю никаких прямых реализаций этого в .Net).

РЕДАКТИРОВАТЬ : Как предлагается в комментарии svick, расстояние Левенштейна также может рассматриваться как лучшая альтернатива расстоянию Хэмминга.

...