Linq — как агрегировать результаты другого запроса

Я хочу взять результаты предложения where в списке, а затем взять этот набор результатов и создать только один новый тип, все поля которого созданы из агрегатов исходного запроса. Итак, учитывая базовый пример ниже, можно ли как-то объединить 2 оператора linq в один? Если в оригинале нет строк, он должен возвращать значение null. Спасибо!

    class Foo
    {
        public int A { get; set; }
        public int B { get; set; }
    }
    List<Foo> lst = GetFooList();

        var q = (from f in lst
                 where f.A > 3
                 select f).ToList();
        if (q.Count != 0)
        {
            var qq = new
            {
                MinA = q.Min(l => l.A),
                MaxB = q.Max(h => h.B),
            };
            // now do something with qq
        }

Обновление: для моей ситуации в исходном наборе много элементов, но после предложения where результирующий набор очень мал. Перечисление второго набора несколько раз не должно быть проблемой. Также мне нужно использовать first и last в наборе, чтобы получить значение из этих записей. Группировка по ответу мне больше подходит. Агрегатный способ очень интересен, и я думаю, что у него есть другое применение.


person RBear    schedule 05.04.2009    source источник
comment
Это относительно сложно, потому что к тому времени, когда вы проверили, есть ли элемент или нет, вы использовали этот первый элемент. Я подозреваю, что есть способ обойти это, но это, вероятно, будет немного хакерским... Подумаю еще.   -  person Jon Skeet    schedule 05.04.2009


Ответы (2)


Это решение повторяет список только один раз с Aggregate(), но для пустых списков возвращает начальное значение. Кстати, начальные значения — int.MaxValue и int.MinValue, потому что Math.Min(int.MaxValue, C) всегда будет возвращать C, а Math.Max(int.MinValue, C) всегда будет возвращать C.

var b = lst.Where(f => f.A > 3)
           .Aggregate(
                  // seed, initial values
                  new
                  {
                     MinA = int.MaxValue,
                     MaxB = int.MinValue
                  },

                  // accumulator function
                  (a,f) => new
                  {
                     MinA = Math.Min(a.MinA , f.A),
                     MaxB = Math.Max(a.MaxB , f.B)
                  });
person Lucas    schedule 05.04.2009

person    schedule
comment
это работает, но будьте осторожны с длинными списками, потому что это будет повторять весь список дважды: g.Min() и g.Max(), как и исходное решение. - person Lucas; 06.04.2009
comment
... на самом деле 3 раза, сначала GroupBy() - person Lucas; 06.04.2009