Преобразовать формат JSON (группировать по)

У меня есть объект JSON следующим образом:

[{
    "name" : "cat",
    "value" : 17,
    "group" : "animal",
},
 {
    "name" : "dog",
    "value" : 6,
    "group" : "animal",
},
 {
    "name" : "snak",
    "value" : 2,
    "group" : "animal",
},
{
    "name" : "tesla",
    "value" : 11,
    "group" : "car",
},
{
    "name" : "bmw",
    "value" : 23,
    "group" : "car",
}]

Я хочу преобразовать этот JSON в формат ниже с помощью JS:

[{
  "name":"animal",
  "children":[
     {"name":"cat", "value":17},
     {"name":"dog", "value":6},
     {"name":"snak", "value":2}
]},
{
  "name":"car",
  "children":[
     {"name":"bmw", "value":11},
     {"name":"tesla", "value":23}
]}]

Я пытаюсь преобразовать и отфильтровать с помощью функции Reduce, но мне не удалось преобразовать в этот формат.

Обновлено:

Код, который я тестировал, был таким.

let groupBy = function(xs, key) {
    return xs.reduce(function(rv, x) {
    (rv[x[key]] = rv[x[key]] || []).push(x);
    return rv;
    }, {});
};

let groubedByExchange=groupBy(JSON_data, 'group');
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
5
1
8 399
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

const arr = [{
    "name": "cat",
    "value": 17,
    "group": "animal",
  },
  {
    "name": "dog",
    "value": 6,
    "group": "animal",
  },
  {
    "name": "snak",
    "value": 2,
    "group": "animal",
  },
  {
    "name": "tesla",
    "value": 11,
    "group": "car",
  },
  {
    "name": "bmw",
    "value": 23,
    "group": "car",
  }
]

const newFormat = arr.reduce((pre, cur) => {
  const group = pre.find(grp => grp.name === cur.group)
  if (group) {
    group.children.push({
      name: cur.name,
      value: cur.value
    })
    return pre
  }

  const newGroup = {
    name: cur.group,
    children: [{
      name: cur.name,
      value: cur.value
    }]
  }
  pre.push(newGroup)
  return pre
}, [])

console.info(newFormat)

ну вот. сначала вы пытаетесь найти эту группу в новом массиве, если она существует, вы добавляете к ней этого ребенка. если нет, вы создаете группу и дочерний массив и вставляете его в массив

Ответ принят как подходящий

Вы можете построить массив и искать ту же группу в массиве.

var array = [{ name: "cat", value: 17, group: "animal" }, { name: "dog", value: 6, group: "animal" }, { name: "snak", value: 2, group: "animal" }, { name: "tesla", value: 11, group: "car" }, { name: "bmw", value: 23, group: "car" }],
    result = array.reduce((r, { group: name, ...object }) => {
        var temp = r.find(o => o.name === name);
        if (!temp) r.push(temp = { name, children: [] });
        temp.children.push(object);
        return r;
    }, []);
    
console.info(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Это было бы моим решением ES6, использующим карту и уменьшение:

const data = [
  {
    name: "cat",
    value: 17,
    group: "animal"
  },
  {
    name: "dog",
    value: 6,
    group: "animal"
  },
  {
    name: "snak",
    value: 2,
    group: "animal"
  },
  {
    name: "tesla",
    value: 11,
    group: "car"
  },
  {
    name: "bmw",
    value: 23,
    group: "car"
  }
];

const grouped = data.reduce((acc, currItem) => {
  const groupKey = currItem.group;
  if (!acc[groupKey]) {
    acc[groupKey] = [currItem];
  } else {
    acc[groupKey].push(currItem);
  }
  return acc;
}, {});

const res = Object.keys(grouped).map(key => ({
  name: key,
  children: grouped[key].map(groupItem => ({
    name: groupItem.name,
    value: groupItem.value
  }))
}));

console.info(res);

Проверьте вывод консоли, чтобы увидеть промежуточные результаты.

Я думаю, что в некоторых других ответах используется ненужный find() (который равен O (n)), в то время как вы можете просто проверить, есть ли уже текущий групповой ключ в O (1).

Я сохраняю сгруппированные результаты в промежуточной переменной grouped для ясности, но все это можно встроить.

Использование Array#from, Array#reduce, Array#concat, деструктуризация, синтаксис распространения и карта.

  1. реорганизовать структуру данных с помощью Map
  2. реструктуризация ваших данных с помощью .map

const data=[{"name":"cat","value":17,"group":"animal",},{"name":"dog","value":6,"group":"animal",},{"name":"snak","value":2,"group":"animal",},{"name":"tesla","value":11,"group":"car",},{"name":"bmw","value":23,"group":"car",}];

const res = Array.from(
  data.reduce((a,{group, ...rest})=>{
    return a.set(group, [rest].concat(a.get(group)||[]));
  }, new Map())
).map(([group, children])=>({group,children}));

console.info(res);

Ну вот. Вы можете использовать lodash для достижения того же.

var data = [{
    "name": "cat",
    "value": 17,
    "group": "animal",
  },
  {
    "name": "dog",
    "value": 6,
    "group": "animal",
  },
  {
    "name": "snak",
    "value": 2,
    "group": "animal",
  },
  {
    "name": "tesla",
    "value": 11,
    "group": "car",
  },
  {
    "name": "bmw",
    "value": 23,
    "group": "car",
  }
]

var result = _(data)
  .groupBy('group')
  .map((group, name) =>
    ({
      name,
      children: _.map(group, ({
        name: name,
        value
      }) => ({
        name,
        value
      }))
    }))
  .value()

console.info(result)
<script src = "https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

Простое решение — создать промежуточный словарь, а затем преобразовать его в структуру вывода.

Вы можете использовать Array.reduce(), Object.entries() и Array.map(), чтобы сделать это:

const data = [
  { "name" : "cat", "value" : 17, "group" : "animal" },
  { "name" : "dog", "value" : 6, "group" : "animal" },
  { "name" : "snak", "value" : 2, "group" : "animal" },
  { "name" : "tesla", "value" : 11, "group" : "car" },
  { "name" : "bmw", "value" : 23, "group" : "car" }
];

const result = Object.entries(data.reduce((acc, { name, value, group }) => {
  acc[group] = (acc[group] || []);
  acc[group].push({ name, value });
  return acc;
}, {})).map(([key, value]) => ({ name: key, children: value }));

console.info(result);

Использование оператора распространения делает его на одну строку короче и по-прежнему читабельным:

const data = [
  { "name" : "cat", "value" : 17, "group" : "animal" },
  { "name" : "dog", "value" : 6, "group" : "animal" },
  { "name" : "snak", "value" : 2, "group" : "animal" },
  { "name" : "tesla", "value" : 11, "group" : "car" },
  { "name" : "bmw", "value" : 23, "group" : "car" }
];

const result = Object.entries(data.reduce((acc, { name, value, group }) => {
  acc[group] = [...(acc[group] || []), { name, value }];
  return acc;
}, {})).map(([key, value]) => ({ name: key, children: value }));

console.info(result);

И на один лайнер короче с оператором запятой:

const data = [
  { "name" : "cat", "value" : 17, "group" : "animal" },
  { "name" : "dog", "value" : 6, "group" : "animal" },
  { "name" : "snak", "value" : 2, "group" : "animal" },
  { "name" : "tesla", "value" : 11, "group" : "car" },
  { "name" : "bmw", "value" : 23, "group" : "car" }
];

const result = Object.entries(data.reduce((acc, { name, value, group }) =>
  (acc[group] = [...(acc[group] || []), { name, value }], acc)
, {})).map(([key, value]) => ({ name: key, children: value }));

console.info(result);

То же самое можно сделать с Object.assign():

const data = [
  { "name" : "cat", "value" : 17, "group" : "animal" },
  { "name" : "dog", "value" : 6, "group" : "animal" },
  { "name" : "snak", "value" : 2, "group" : "animal" },
  { "name" : "tesla", "value" : 11, "group" : "car" },
  { "name" : "bmw", "value" : 23, "group" : "car" }
];

const result = Object.entries(data.reduce((acc, { name, value, group }) =>
  Object.assign(acc, { [group]: [...(acc[group] || []), { name, value }] })
, {})).map(([key, value]) => ({ name: key, children: value }));

console.info(result);

И, наконец, немного длиннее, но с многоразовой функцией groupBy:

const data = [
  { "name" : "cat", "value" : 17, "group" : "animal" },
  { "name" : "dog", "value" : 6, "group" : "animal" },
  { "name" : "snak", "value" : 2, "group" : "animal" },
  { "name" : "tesla", "value" : 11, "group" : "car" },
  { "name" : "bmw", "value" : 23, "group" : "car" }
];

const groupBy = prop => data => {
  return data.reduce((dict, item) => {
    const { [prop]: _, ...rest } = item;
    dict[item[prop]] = [...(dict[item[prop]] || []), rest];
    return dict;
  }, {});
};

const result = Object.entries(groupBy('group')(data))
  .map(([key, value]) => ({ name: key, children: value }));

console.info(result);

Хорошее использование Object.entries. Мне также нравится acc[group] = (acc[group] || []);, чтобы избежать оператора if. Это должен быть принятый ответ imo.

fabio.sussetto 18.02.2019 23:37
const transform = things =>
  things.reduce((acc, { name, value, group }) => {
    const existingGroup = acc.find(g => g.name === group) || {};
    return [
      ...acc.filter(g => g.name !== group),
      {
        ...existingGroup,
        name: group,
        children: [...(existingGroup.children || []), { name, value }],
      },
    ];
  }, []);

Другие вопросы по теме