Лучший способ создать вложенный массив с количеством, равным общему количеству детей - PullRequest
1 голос
/ 29 марта 2020

У меня есть структура входных данных, такая как

const i = [
  { Time: "Breakfast", City: "Bangalore", Area: "Bellandur", count: 12 },
  { Time: "Breakfast", City: "Hyderabad", Area: "LBNagar", count: 19 },
  { Time: "Lunch", City: "Bangalore", Area: "Koramangala", count: 22 },
  { Time: "Dinner", City: "Hyderabad", Area: "Koti", count: 10 },
  { Time: "Dinner", City: "Bangalore", Area: "Bellandur", count: 16 },
  { Time: "Lunch", City: "Hyderabad", Area: "LBNagar", count: 28 },
  { Time: "Breakfast", City: "Bangalore", Area: "Bellandur", count: 11 },
  { Time: "Lunch", City: "Hyderabad", Area: "Koti", count: 24 },
  { Time: "Dinner", City: "Bangalore", Area: "Koramangala", count: 27 },
  { Time: "Breakfast", City: "Bangalore", Area: "Bellandur", count: 22 },
  { Time: "Breakfast", City: "Hyderabad", Area: "Manikonda", count: 11 },
  { Time: "Dinner", City: "Hyderabad", Area: "Manikonda", count: 10 },
  { Time: "Lunch", City: "Bangalore", Area: "Bellandur", count: 17 }
];

Ожидаемая преобразованная структура данных должна быть вложенным массивом с count prop, равным сумме count значений детей

[
  {
    "d": "Breakfast",
    "count": 42,
    "children": [
      {
        "d": "Bangalore",
        "count": 12,
        "children": [
          {
            "d": "Bellandur",
            "count": 12,
            "children": []
          }
        ]
      },
      {
        "d": "Hyderabad",
        "count": 30,
        "children": [
          {
            "d": "LBNagar",
            "count": 19,
            "children": []
          },
          {
            "d": "Manikonda",
            "count": 11,
            "children": []
          }
        ]
      }
    ]
  },
  {
    "d": "Lunch",
    "count": 91,
    "children": [
      {
        "d": "Bangalore",
        "count": 39,
        "children": [
          {
            "d": "Koramangala",
            "count": 22,
            "children": []
          },
          {
            "d": "Bellandur",
            "count": 17,
            "children": []
          }
        ]
      },
      {
        "d": "Hyderabad",
        "count": 52,
        "children": [
          {
            "d": "LBNagar",
            "count": 28,
            "children": []
          },
          {
            "d": "Koti",
            "count": 24,
            "children": []
          }
        ]
      }
    ]
  },
  {
    "d": "Dinner",
    "count": 63,
    "children": [
      {
        "d": "Hyderabad",
        "count": 20,
        "children": [
          {
            "d": "Koti",
            "count": 10,
            "children": []
          },
          {
            "d": "Manikonda",
            "count": 10,
            "children": []
          }
        ]
      },
      {
        "d": "Bangalore",
        "count": 43,
        "children": [
          {
            "d": "Bellandur",
            "count": 16,
            "children": []
          },
          {
            "d": "Koramangala",
            "count": 27,
            "children": []
          }
        ]
      }
    ]
  }
]

To достичь вышеуказанного результата, у меня есть фрагмент

const input = [
  { Time: "Breakfast", City: "Bangalore", Area: "Bellandur", count: 12 },
  { Time: "Breakfast", City: "Hyderabad", Area: "LBNagar", count: 19 },
  { Time: "Lunch", City: "Bangalore", Area: "Koramangala", count: 22 },
  { Time: "Dinner", City: "Hyderabad", Area: "Koti", count: 10 },
  { Time: "Dinner", City: "Bangalore", Area: "Bellandur", count: 16 },
  { Time: "Lunch", City: "Hyderabad", Area: "LBNagar", count: 28 },
  { Time: "Breakfast", City: "Bangalore", Area: "Bellandur", count: 11 },
  { Time: "Lunch", City: "Hyderabad", Area: "Koti", count: 24 },
  { Time: "Dinner", City: "Bangalore", Area: "Koramangala", count: 27 },
  { Time: "Breakfast", City: "Bangalore", Area: "Bellandur", count: 22 },
  { Time: "Breakfast", City: "Hyderabad", Area: "Manikonda", count: 11 },
  { Time: "Dinner", City: "Hyderabad", Area: "Manikonda", count: 10 },
  { Time: "Lunch", City: "Bangalore", Area: "Bellandur", count: 17 }
];

// convert nested array into map
// Ex: {Breakfast: { Bangalore: {Bellandur: 40 }, ... } ... }}}
const nestedMap = input.reduce((acc, v) => {
  if (!acc[v["Time"]]) {
    acc[v["Time"]] = {};
  }

  if (!acc[v["Time"]][v["City"]]) {
    acc[v["Time"]][v["City"]] = {};
  }

  if (!acc[v["Time"]][v["City"]][v["Area"]]) {
    acc[v["Time"]][v["City"]][v["Area"]] = v["count"];
  }

  return acc;
}, {});

const summer = (o, i) =>
  typeof o === "number"
    ? i + o
    : Object.values(o).reduce((acc, v) => acc + summer(v, i), 0);

const aggregator = o => {
  return typeof o === "number"
    ? []
    : Object.entries(o).map(([n, child]) => ({
        d: n,
        count: summer(child, 0),
        children: aggregator(child)
      }));
};

const result = aggregator(nestedMap);

console.log(JSON.stringify(result, undefined, 2));

Думаю, мой фрагмент работает отлично, он включает в себя много итераций. Сначала выполняется преобразование в карту и одна итерация (функция summer) для подсчета количества дочерних элементов, а другая итерация (функция aggregator) - для формирования вложенного массива.

Я ищу лучшее решение для повышения производительности. Заранее спасибо!

1 Ответ

1 голос
/ 29 марта 2020

Можно использовать более сжатый подход с массивом вложенных ключей и искать объект со значением на уровне.

Затем добавить счетчик и вернуть фактический объект.

Такой подход предотвращает слежку за массивами детей

var data = [{ Time: "Breakfast", City: "Bangalore", Area: "Bellandur", count: 12 }, { Time: "Breakfast", City: "Hyderabad", Area: "LBNagar", count: 19 }, { Time: "Lunch", City: "Bangalore", Area: "Koramangala", count: 22 }, { Time: "Dinner", City: "Hyderabad", Area: "Koti", count: 10 }, { Time: "Dinner", City: "Bangalore", Area: "Bellandur", count: 16 }, { Time: "Lunch", City: "Hyderabad", Area: "LBNagar", count: 28 }, { Time: "Breakfast", City: "Bangalore", Area: "Bellandur", count: 11 }, { Time: "Lunch", City: "Hyderabad", Area: "Koti", count: 24 }, { Time: "Dinner", City: "Bangalore", Area: "Koramangala", count: 27 }, { Time: "Breakfast", City: "Bangalore", Area: "Bellandur", count: 22 }, { Time: "Breakfast", City: "Hyderabad", Area: "Manikonda", count: 11 }, { Time: "Dinner", City: "Hyderabad", Area: "Manikonda", count: 10 }, { Time: "Lunch", City: "Bangalore", Area: "Bellandur", count: 17 }],
    keys = ['Time', 'City', 'Area'],
    result = data
        .reduce((r, o) => {
            keys.reduce((p, k) => {
                var temp = (p.children = p.children || []).find(q => q.d === o[k]);
                if (!temp) p.children.push(temp = { d: o[k], count: 0 });
                temp.count += o.count;
                return temp;
            }, r);
            return r;
        }, { children: [] })
        .children;

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
...