Удаление дубликатов Linq с изюминкой

У меня есть список, содержащий все элементы статуса каждого заказа. У меня проблема в том, что мне нужно удалить все элементы, для которых комбинация status -> logdate не является самой высокой.

e.g

        var inputs = new List<StatusItem>();
        //note that the 3th id is simply a modifier that adds that amount of secs
        //to the current datetime, to make testing easier
        inputs.Add(new StatusItem(123, 30, 1));
        inputs.Add(new StatusItem(123, 40, 2));
        inputs.Add(new StatusItem(123, 50, 3));
        inputs.Add(new StatusItem(123, 40, 4));
        inputs.Add(new StatusItem(123, 50, 5));

        inputs.Add(new StatusItem(100, 20, 6));
        inputs.Add(new StatusItem(100, 30, 7));
        inputs.Add(new StatusItem(100, 20, 8));
        inputs.Add(new StatusItem(100, 30, 9));
        inputs.Add(new StatusItem(100, 40, 10));
        inputs.Add(new StatusItem(100, 50, 11));
        inputs.Add(new StatusItem(100, 40, 12));

        var l = from i in inputs
                group i by i.internalId
                    into cg
                    select
                             from s in cg
                             group s by s.statusId
                                 into sg
                                 select sg.OrderByDescending(n => n.date).First()
                    ;

edit: для удобства я также добавляю определение класса.

  public class StatusItem
  {
            public int internalId;
            public int statusId;
            public DateTime date;

            public StatusItem(int internalId, int statusId, int secMod)
            {
                this.internalId = internalId;
                this.statusId = statusId;
                date = DateTime.Now.AddSeconds(secMod);
            }
  } 

Это создает список, который возвращает мне следующее:

заказ 123 статус 30 дата 09.04.2010 18:44:21
заказ 123 статус 40 дата 09.04.2010 18:44:24
заказ 123 статус 50 дата 09.04.2010 6: 44:25 вечера

заказ 100 статус 20 дата 09.04.2010 18:44:28
заказ 100 статус 30 дата 09.04.2010 18:44:29
заказ 100 статус 40 дата 09.04.2010 6: 16:32
заказ 100 статус 50 дата 09.04.2010 18:44:31

Это ПОЧТИ правильно. Однако эту последнюю строку со статусом 50 также необходимо отфильтровать, поскольку она была отменена статусом 40 в списке истории. Это видно по тому, что его дата ниже, чем у «последнего» статус-элемента со статусом 40.

Я надеялся, что кто-то может дать мне несколько советов, потому что я застрял.

Изменить: окончательное полное решение:

  var k = from sg in
                    from i in inputs
                     group i by i.internalId
                         into cg
                         select
                                  from s in cg
                                  group s by s.statusId
                                      into sg
                                      select sg.OrderByDescending(n => n.date).First()
                from s in sg
                where s.date >= sg.Where(n => n.statusId <= s.statusId).Max(n => n.date)
                group s by s.internalId
                    into si
                    from x in si
                    select x;

person Danthar    schedule 09.04.2010    source источник


Ответы (2)


Похоже, в настоящее время у вас нет ничего, выполняющего фильтрацию, необходимую для даты, поэтому вам нужно что-то с этим сделать.

Навскидку что-то вроде этого выполнит дополнительную фильтрацию:

        var k = from sg in l
                from s in sg
                where s.date >= sg.Where(n => n.statusId <= s.statusId).Max(n => n.date)
                group s by s.internalId;

Не проверял, поэтому группировка может быть не такой, как вы хотите, и сравнения могут быть обратными, но что-то вроде этого должно фильтроваться. >= и <= вместо > или < должны означать, что статус всегда будет сравниваться сам с собой и не придется иметь дело с пустым набором в совокупных задачах.

person Tanzelax    schedule 09.04.2010

Это не совсем в той же форме, что и у вас, но дает правильный результат. Я создал класс элемента состояния со свойствами i, j и k. Не уверен, какие имена вы использовали для них.

var keys = inputs.Select(
    input =>
        new { i = input.i, j = input.j })
.Distinct();

var maxes = keys.Select(
    ints =>
        inputs.First(
            input =>
                input.i == ints.i
             && input.j == ints.j
             && input.k == inputs.Where(
                               i =>
                                   i.i == ints.i
                                && i.j == ints.j
                            ).Select(i => i.k).Max()));
person Greg Bogumil    schedule 09.04.2010
comment
Неа. После того, как я перевел i, j и k в имена свойств, я использую im и получаю тот же результат, что и моя собственная реализация. - person Danthar; 09.04.2010
comment
Это странно. Я вывел результаты и получил это. 123 30 1 123 40 4 123 50 5 100 20 8 100 30 9 100 40 12 100 50 11 - person Greg Bogumil; 12.04.2010