[4]
// Абрамян М.Э. ТЕХНОЛОГИЯ LINQ НА ПРИМЕРАХ. М.: ДМК-Пресс, 2014.
// Глава 6. Примеры решения задач из группы LinqObj
//     6.1. Простое задание на обработку отдельной последовательности
// LinqObj4: правильное решение (с.191, внизу)
begin
  Task('LinqObj4');
  var r := ReadAllLines(ReadString)
    .Select(e ->
      begin
        var s := e.Split(' ');
        result := new class (
          hours := StrToInt(s[2]),
          code := StrToInt(s[3])
        );
      end)
    .GroupBy(e -> e.code,
      (k, ee) -> new class(k, sum := ee.Sum(c -> c.hours) ))
    .OrderByDescending(e -> e.sum).ThenBy(e -> e.k)
    .Select(e -> e.sum + ' ' + e.k);
    WriteAllLines(ReadString, r);
end.
[41]
// Абрамян М.Э. ТЕХНОЛОГИЯ LINQ НА ПРИМЕРАХ. М.: ДМК-Пресс, 2014.
// Глава 6. Примеры решения задач из группы LinqObj
//     6.2. Более сложные задания на обработку отдельных последовательностей
// LinqObj41: правильное решение (с.196)
begin
  Task('LinqObj41');
  var m := ReadInteger;
  var r := ReadAllLines(ReadString)
    .Select(e ->
      begin
        var s := e.Split(' ');
        result := new class (
          brand := StrToInt(s[0]),
          street := s[1],
          price := StrToInt(s[3])
        );
      end)
    .Where(e -> e.brand = m)
    .GroupBy(e -> e.street,
      (k, ee) -> new class ( street := k, max := ee.Max(e -> e.price) ))
    .OrderBy(e -> e.max).ThenBy(e -> e.street)
    .Select(e -> e.max + ' ' + e.street)
    .DefaultIfEmpty('Нет');
  WriteAllLines(ReadString, r);
end.
[61]
// Абрамян М.Э. ТЕХНОЛОГИЯ LINQ НА ПРИМЕРАХ. М.: ДМК-Пресс, 2014.
// Глава 6. Примеры решения задач из группы LinqObj
//     6.2. Более сложные задания на обработку отдельных последовательностей
// LinqObj61: правильное решение (с.199-200)
begin
    Task('LinqObj61');
    var subjects : array of string := ( 'Алгебра', 'Геометрия', 'Информатика' );
    var culture := new System.Globalization.CultureInfo('en-US');
    var r := ReadAllLines(ReadString)
      .Select(e ->
      begin
          var s := e.Split(' ');
          result := new class
          (
              name := s[0] + ' ' + s[1],
              subj := s[3],
              mark := StrToInt(s[4])
          );
      end)
      .GroupBy(e -> e.name, (k, ee) -> new class
      (
          name := k,
          avrs := subjects
            .GroupJoin(ee, s -> s, e -> e.subj,
              (s1, ee1) -> ee1.Select(e1 -> e1.mark)
            .DefaultIfEmpty().Average())
      ))
      .OrderBy(e -> e.name)
      .Select(e -> e.name + e.avrs.Aggregate('',
         (a, d) -> a + ' ' + d.ToString('f2', culture)));
    WriteAllLines(ReadString, r);
end.
[98]
// Абрамян М.Э. ТЕХНОЛОГИЯ LINQ НА ПРИМЕРАХ. М.: ДМК-Пресс, 2014.
// Глава 6. Примеры решения задач из группы LinqObj
//     6.3. Обработка взаимосвязанных последовательностей
// LinqObj98: правильное решение (с.215, вверху)
begin
    Task('LinqObj98');
    var B := ReadAllLines(ReadString)
      .Select(e ->
      begin
          var s := e.Split(' ');
          result := new class
          (
              art := s[1],
              cat := s[2]
          );
      end);
    var C := ReadAllLines(ReadString)
      .Select(e ->
      begin
          var s := e.Split(' ');
          result := new class
          (
              discount := StrToInt(s[0]),
              code := s[1],
              shop := s[2]
          );
      end);
    var D := ReadAllLines(ReadString)
      .Select(e ->
      begin
          var s := e.Split(' ');
          result := new class
          (
              art := s[0],
              price := StrToInt(s[1]),
              shop := s[2]
          );
      end);
    var E := ReadAllLines(ReadString)
      .Select(e ->
      begin
          var s := e.Split(' ');
          result := new class
          (
              code := s[0],
              art := s[1],
              shop := s[2]
          );
      end);
    var discounts := E.Join(B, e1 -> e1.art, e2 -> e2.art,
        (e1, e2) -> new class ( e1.code, e1.art, e1.shop, e2.cat ))
      .Join(D, e1 -> e1.art + e1.shop, e2 -> e2.art + e2.shop,
        (e1, e2) -> new class ( e1.code, e1.shop, e1.cat, e2.price ))
      .GroupJoin(C, e1 -> e1.code + e1.shop, e2 -> e2.code + e2.shop,
        (e1, ee2) -> new class
        (
            cat_shop := e1.cat + ' ' + e1.shop,
            discount := ee2.Select(e -> e.discount)
              .FirstOrDefault() * e1.price div 100
        ));
    var cats := B.GroupBy(e -> e.cat, (k, ee) -> k);
    var shops := E.GroupBy(e -> e.shop, (k, ee) -> k);
    var r := cats
      .SelectMany(e1 -> shops.Select(e2 -> e1 + ' ' + e2))
      .OrderBy(e -> e)
      .GroupJoin(discounts, e1 -> e1, e2 -> e2.cat_shop,
        (e1, ee2) -> e1 + ' ' +
        IntToStr(ee2.Select(e -> e.discount).DefaultIfEmpty(-1).Sum()));
    WriteAllLines(ReadString, r);
end.


