Как группировать и суммировать в стиле LINQ в JavaScript - PullRequest
0 голосов
/ 10 марта 2020

Я схожу с ума по этому поводу. Может быть, вы могли бы помочь.

Предположим, что у вас есть следующее. NET классы:

Учитель:

public class Teacher
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public Class[] Classes { get; set; }
}

Класс

public class Class
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Attendee[] Attendees { get; set; }
}

Участник

public class Attendee
{
 public int Id { get; set; }
 public string FirstName { get; set; }
 public string LastName { get; set; }
 public int Presences { get; set; }
}

Согласно этой структуре мы берем следующие данные, например:

var teachers = 
    new Teacher[] {
        new Teacher{ Id = 1, FirstName="Michael", LastName = "Knight",
            Classes = new Class[]{
                new Class{ Id = 1, Name = "Maths",
                    Attendees = new Attendee[]{
                        new Attendee{ Id = 1, FirstName = "Templeton", LastName = "Peck", Presences=22 },
                        new Attendee{ Id = 2, FirstName = "Stringfellow", LastName = "Hawke", Presences=20 }
                    }
                },
                new Class{ Id = 1, Name = "English",
                    Attendees = new Attendee[]{
                        new Attendee{ Id = 3, FirstName = "Morris", LastName = "Buttermaker", Presences=25 },
                        new Attendee{ Id = 4, FirstName = "Ben", LastName = "Matlock", Presences=18 },
                        new Attendee{ Id = 5, FirstName = "Kelly", LastName = "Taylor", Presences=22 },
                        new Attendee{ Id = 5, FirstName = "Marty", LastName = "McFly", Presences=0 }
                    }
                }
            }
        },
        new Teacher{ Id = 2, FirstName="Murray", LastName = "Bozinsky",
            Classes = new Class[]{
                new Class{ Id = 1, Name = "Maths",
                    Attendees = new Attendee[]{
                        new Attendee{ Id = 6, FirstName = "Luke", LastName = "Duke", Presences=21 },
                        new Attendee{ Id = 7, FirstName = "Bo", LastName = "Darville", Presences=26 },
                        new Attendee{ Id = 8, FirstName = "Frank", LastName = "Columbo", Presences=20 }
                    }
                },
                new Class{ Id = 1, Name = "English",
                    Attendees = new Attendee[]{
                        new Attendee{ Id = 9, FirstName = "Philip", LastName = "Banks", Presences=28 },
                        new Attendee{ Id = 10, FirstName = "Lynn", LastName = "Tanner", Presences=18 }
                    }
                }
            }
        }
    };

Что я сейчас хочу сделать, это подвести итоги всех присутствующих учителей. В LINQ я бы сделал это следующим образом:

var result = teachers
    .Select(p => 
        new { 
            TeacherFirstName = p.FirstName, 
            TeacherLastName = p.LastName, 
            Presences = p.Classes
                .SelectMany(q => q.Attendees.Select(r => r.Presences))
                .Sum() });

Что дает мне (как JSON):

[
    {"TeacherFirstName":"Michael","TeacherLastName":"Knight","Presences":107}, 
    {"TeacherFirstName":"Murray","TeacherLastName":"Bozinsky","Presences":113}
]

Как я могу сделать это с JavaScript, взяв следующее JSON объект:

[
    {
        "Id":1,"FirstName":"Michael","LastName":"Knight",
        "Classes":
        [
            {
                "Id":1,"Name":"Maths",
                "Attendees":
                [
                    {"Id":1,"FirstName":"Templeton","LastName":"Peck","Presences":22}, 
                    {"Id":2,"FirstName":"Stringfellow","LastName":"Hawke","Presences":20}
                ]
            }, 
            {
                "Id":1,"Name":"English",
                "Attendees":
                [
                    {"Id":3,"FirstName":"Morris","LastName":"Buttermaker","Presences":25}, 
                    {"Id":4,"FirstName":"Ben","LastName":"Matlock","Presences":18}, 
                    {"Id":5,"FirstName":"Kelly","LastName":"Taylor","Presences":22}, 
                    {"Id":5,"FirstName":"Marty","LastName":"McFly","Presences":0}
                ]
            }
        ]
    }, 
    {
        "Id":2,"FirstName":"Murray","LastName":"Bozinsky",
        "Classes":
        [
            {
                "Id":1,"Name":"Maths",
                "Attendees":
                [
                    {"Id":6,"FirstName":"Luke","LastName":"Duke","Presences":21},
                    {"Id":7,"FirstName":"Bo","LastName":"Darville","Presences":26},
                    {"Id":8,"FirstName":"Frank","LastName":"Columbo","Presences":20}
                ]
            },
            {
                "Id":1,"Name":"English",
                "Attendees":
                [
                    {"Id":9,"FirstName":"Philip","LastName":"Banks","Presences":28}, 
                    {"Id":10,"FirstName":"Lynn","LastName":"Tanner","Presences":18}
                ]
            }
        ]
    }
]

Я играл вокруг с reduce и map. Но я просто не могу заставить его работать. У вас есть подсказка, как это можно сделать на одном (или двух, или трех, ...) вкладышах?

Заранее спасибо.

Ответы [ 3 ]

3 голосов
/ 10 марта 2020

С LINQ для Javascript вы можете взять почти тот же код для получения суммированного результата.

var teachers = [{ Id: 1, FirstName: "Michael", LastName: "Knight", Classes: [{ Id: 1, Name: "Maths", Attendees: [{ Id: 1, FirstName: "Templeton", LastName: "Peck", Presences: 22 }, { Id: 2, FirstName: "Stringfellow", LastName: "Hawke", Presences: 20 }] }, { Id: 1, Name: "English", Attendees: [{ Id: 3, FirstName: "Morris", LastName: "Buttermaker", Presences: 25 }, { Id: 4, FirstName: "Ben", LastName: "Matlock", Presences: 18 }, { Id: 5, FirstName: "Kelly", LastName: "Taylor", Presences: 22 }, { Id: 5, FirstName: "Marty", LastName: "McFly", Presences: 0 }] }] }, { Id: 2, FirstName: "Murray", LastName: "Bozinsky", Classes: [{ Id: 1, Name: "Maths", Attendees: [{ Id: 6, FirstName: "Luke", LastName: "Duke", Presences: 21 }, { Id: 7, FirstName: "Bo", LastName: "Darville", Presences: 26 }, { Id: 8, FirstName: "Frank", LastName: "Columbo", Presences: 20 }] }, { Id: 1, Name: "English", Attendees: [{ Id: 9, FirstName: "Philip", LastName: "Banks", Presences: 28 }, { Id: 10, FirstName: "Lynn", LastName: "Tanner", Presences: 18 }] }] }],
    result = Enumerable.From(teachers)
        .Select(p => ({
            TeacherFirstName: p.FirstName,
            TeacherLastName: p.LastName,
            Presences: Enumerable.From(p.Classes)
                .SelectMany(q => Enumerable.From(q.Attendees).Select('$.Presences'))
                .Sum()
        }))
        .ToArray();

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/linq.js/2.2.0.2/linq.js"></script>
2 голосов
/ 10 марта 2020

Конечно. Одно выражение карты:

const transformed = data.map(
  ({ FirstName, LastName, Classes }) => ({
    TeacherFirstName: FirstName,
    TeacherLastName: LastName,
    Presences: Classes.map(c =>
      c.Attendees.reduce(
        (acc, { Presences }) => acc + Presences,
        0,
      ),
    ).reduce((acc, value) => acc + value, 0),
  }),
);

приводит к

[
  {
    TeacherFirstName: 'Michael',
    TeacherLastName: 'Knight',
    Presences: 107
  },
  {
    TeacherFirstName: 'Murray',
    TeacherLastName: 'Bozinsky',
    Presences: 113
  }
]

Добавление вспомогательной функции для суммирования массива чисел делает вещи, возможно, более читабельными, чем при использовании, уменьшает:

const sum = numbers => numbers.reduce((acc, n) => acc + n, 0);

const transformed = data.map(
  ({ FirstName, LastName, Classes }) => ({
    TeacherFirstName: FirstName,
    TeacherLastName: LastName,
    Presences: sum(
      Classes.map(c => sum(c.Attendees.map(a => a.Presences))),
    ),
  }),
);
1 голос
/ 10 марта 2020

Можно использовать метод reduce для суммирования нужных элементов.

Это короткая версия:

const shortVersion = arr.reduce((a, c)=> {
  let presences = c.Classes.reduce((a1, c1) => (a1 += c1.Attendees.reduce((a2, {Presences}) => ( a2+=Presences, a2 ), 0)), 0);
  a.push({TeacherFirstName: c.FirstName, TeacherLastName: c.LastName, Presences: presences});
  return a;
}, []);

Это более длинная версия, но, на мой взгляд, более отлаживаемая и читаемая:

const result = arr.reduce((a, c)=> {
  let presences = c.Classes.reduce((a1, c1) => {
      const result = c1.Attendees.reduce((a2, {Presences}) => ( a2+=Presences, a2 ), 0);
      a1 += result;
      return a1;
    }, 0);
  a.push({TeacherFirstName: c.FirstName, TeacherLastName: c.LastName, Presences: presences});
  return a;
}, []);

Пример:

let arr = [
  {
      "Id":1,"FirstName":"Michael","LastName":"Knight",
      "Classes":
      [
          {
              "Id":1,"Name":"Maths",
              "Attendees":
              [
                  {"Id":1,"FirstName":"Templeton","LastName":"Peck","Presences":22},
                  {"Id":2,"FirstName":"Stringfellow","LastName":"Hawke","Presences":20}
              ]
          },
          {
              "Id":1,"Name":"English",
              "Attendees":
              [
                  {"Id":3,"FirstName":"Morris","LastName":"Buttermaker","Presences":25},
                  {"Id":4,"FirstName":"Ben","LastName":"Matlock","Presences":18},
                  {"Id":5,"FirstName":"Kelly","LastName":"Taylor","Presences":22},
                  {"Id":5,"FirstName":"Marty","LastName":"McFly","Presences":0}
              ]
          }
      ]
  },
  {
      "Id":2,"FirstName":"Murray","LastName":"Bozinsky",
      "Classes":
      [
          {
              "Id":1,"Name":"Maths",
              "Attendees":
              [
                  {"Id":6,"FirstName":"Luke","LastName":"Duke","Presences":21},
                  {"Id":7,"FirstName":"Bo","LastName":"Darville","Presences":26},
                  {"Id":8,"FirstName":"Frank","LastName":"Columbo","Presences":20}
              ]
          },
          {
              "Id":1,"Name":"English",
              "Attendees":
              [
                  {"Id":9,"FirstName":"Philip","LastName":"Banks","Presences":28},
                  {"Id":10,"FirstName":"Lynn","LastName":"Tanner","Presences":18}
              ]
          }
      ]
  }
]


const result = arr.reduce((a, c)=> {
  let presences = c.Classes.reduce((a1, c1) => {
      const result = c1.Attendees.reduce((a2, {Presences}) => ( a2+=Presences, a2 ), 0);
      a1 += result;
      return a1;
    }, 0);
  a.push({TeacherFirstName: c.FirstName, TeacherLastName: c.LastName, Presences: presences});
  return a;
}, []);


const shortVersion = arr.reduce((a, c)=> {
  let presences = c.Classes.reduce((a1, c1) => (a1 += c1.Attendees.reduce((a2, {Presences}) => ( a2+=Presences, a2 ), 0)), 0);
  a.push({TeacherFirstName: c.FirstName, TeacherLastName: c.LastName, Presences: presences});
  return a;
}, []);


console.log(result);
console.log(shortVersion);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...