Transform JSON structure (Group data)

Here is the JSON object I am working with:

[{
    "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",
}]

I am trying to transform this JSON into the following format using JavaScript:

[{
  "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}
]}]

I attempted to achieve this conversion and filtering using the Reduce function, but I was unable to get it in the desired format.

EDIT:

The code snippet I tested for this purpose is as follows:

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');

Answer №1

One way to solve this problem is by creating an array and then searching for elements with the same group in the array.

var array = [{ name: "cat", value: 17, group: "animal" }, { name: "dog", value: 6, group: "animal" }, { name: "snake", 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.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Answer №2

An effective approach involves creating an intermediary dictionary and then converting it to the desired output structure.

To achieve this, you can utilize Array.reduce(), Object.entries(), and Array.map() as demonstrated below:

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.log(result);

The use of spread operator allows for a more concise code without compromising readability:

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.log(result);

A further optimization using the comma operator results in even shorter code:

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.log(result);

Additionally, the same outcome can be achieved using 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.log(result);

Finally, there's a slightly longer but reusable implementation with a groupBy function:

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.log(result);

Answer №3

Utilizing Array#from, Array#reduce, Array#concat, destructuring, spread syntax along with the Map object.

  1. Reconfigure your data structure using a Map
  2. Restructure your data by utilizing .map

const information=[{"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 = Array.from(
  information.reduce((accumulator,{group, ...others})=>{
    return accumulator.set(group, [others].concat(accumulator.get(group)||[]));
  }, new Map())
).map(([group, children])=>({group,children}));

console.log(result);

Answer №4

const items = [{
    "name": "apple",
    "quantity": 5,
    "type": "fruit",
  },
  {
    "name": "banana",
    "quantity": 8,
    "type": "fruit",
  },
  {
    "name": "carrot",
    "quantity": 3,
    "type": "vegetable",
  },
  {
    "name": "pepper",
    "quantity": 6,
    "type": "vegetable",
  }
]

const organizedItems = items.reduce((prev, current) => {
  const type = prev.find(itemType => itemType.name === current.type)
  if (type) {
    type.items.push({
      name: current.name,
      quantity: current.quantity
    })
    return prev
  }

  const newType = {
    name: current.type,
    items: [{
      name: current.name,
      quantity: current.quantity
    }]
  }
  prev.push(newType)
  return prev
}, [])

console.log(organizedItems)

Here is an example. You first attempt to locate the specified group in the updated array. If it is found, you append the child element to it. If not, a new group with a children array is created and added to the array.

Answer №5

Here is a solution using the lodash library:

var data = [{
    "name": "cat",
    "value": 17,
    "group": "animal",
  },
  {
    "name": "dog",
    "value": 6,
    "group": "animal",
  },
  {
    "name": "snake",
    "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.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

Answer №6

Here is my ES6 solution utilizing map and reduce:

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.log(res);

View the console output to observe the results as the code progresses.

I believe some other responses make use of an unnecessary find() method (which has a time complexity of O(n)), whereas you can simply check if a current group key already exists in O(1).

I have opted to store the grouped outcomes in an intermediate variable grouped for clarity purposes, but it is possible to consolidate everything.

Answer №7

function groupThings(things) {
  return 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 }],
      },
    ];
  }, []);
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Node-zookeeper-client executes the callback for getData method only one time

I have been using node-zookeeper-client in my Node.js server. Everything works smoothly when I watch a znode data with the getData method for the first time. However, I encounter an issue when updating the node (using the ZK-Web user interface) - the wat ...

Consolidate repeated entries in a Json file

Here is the structure of my JSON file [ { "Hugo_Symbol": "FLT3", "HGVSp_Short": "p.T227M", "Other": { "Type": "Renal", "Drug": "Sunitinib", ...

Display hierarchical JSON data in an Angular table

I'm attempting to display nested data from JSON in a table, but I'm having trouble achieving success. My JSON data:- $scope.data = [ { "$id": "1", "Folder": [ { "Name": "Windows-Desktop", "CPU": "2", ...

Tips for creating a script that is compatible with both Java and C++

We currently offer both Java and C++ versions of our distributed messaging system product. I am in the process of developing a framework to conduct system testing across multiple servers. In order to accomplish this, I need a "test coordinator" process th ...

Tips for refreshing an element after modifying a data-* attribute

I have an element that has the following CSS style: #element:after { content: attr(data-percent); } In an attempt to change the data-percent attribute using jQuery, I used this code: $('#element').data('percent', '50%'); ...

What makes Angular date pickers sluggish?

Have you ever noticed that Angular JS date pickers consume a lot of CPU? When multiple date pickers are present on a page, they can noticeably reduce the site's speed. Is there a way to minimize this issue? Take for example the official Angular for ...

"Transforming a static navbar to a fixed position causes the page to jump

Having some difficulty figuring this out. I'm working on a bootstrap navbar that transitions from static to fixed when the user scrolls past the logo at the top. Everything seems to be working fine, except for when the navbar reaches the top, it sudde ...

Unreliable Response from JEditable

I have encountered an unusual behavior while using the JEditable jQuery plugin to update data on my webpage. One specific field is not updating as expected, instead displaying the following message: EM29UPDATE NetLog SET grid = 'EM29&apo ...

JavaScript: A pair of radio button selections

I'm facing an issue with a short form that has two questions and radio buttons for answers. When the first question is answered "No," I used JS code to disable options for the second question, which works fine. However, if the answer is changed back t ...

When accessing a page from a link, JavaScript sometimes does not immediately execute on the first attempt

I'm encountering a strange issue in my rails application, where a template fails to execute the Javascript code the first time it is loaded via a link on my home page. This problem only occurs when accessed through the link for the first time. I' ...

ElementUI Cascader not rendering properly

Utilizing elementUI's cascading selector to present data, I have crafted this code in accordance with the official documentation. <el-cascader v-model="address" :options="addressOptions" :props="{expandTrigger: 'hover'}" ...

Implementing an Onclick function in HTML

I have an HTML code and I am looking to add an onclick event for a button named GET DATA. When the button is clicked, I want to send data for userId and categoryId to a PHP file. Can someone help me implement this functionality in my existing code? Here ...

Is there a way to monitor and trigger a function in jQuery when a loaded PHP file is modified?

I am currently working on a dynamic dashboard that automatically updates every few seconds to display new information fetched from a PHP file. My goal is to trigger an alert only when there is a change in the data itself, rather than just a refresh. In ord ...

Steps to create an iframe that opens in a new window

I'm facing an issue with the iframe sourced from flickr. My website includes an embedded flickr iframe to showcase a gallery without the hassle of creating a slider, resizing images, and extracting thumbnails. Given that this site belongs to a frien ...

Decoding a nested JSON array in C#

I'm brand new to c# and struggling with retrieving a JSON array of arrays from a 2D array. In my JSON file, I have data representing student grades like this: [ [10,5,4], [9,6,3] ] When trying to parse this JSON using JArray, I encounter an ...

Using jQuery.ajax and not retrieved using a GET request

I'm attempting to extract the value (adults) from a select option field using a GET request with AJAX. I am able to extract the value from the URL by displaying an alert with the URL in the jQuery function. However, I am unable to retrieve the value w ...

Converting an array or JSON to a string

Converting a string to an array: $string = '[{"name":"jack","address":"who knows"},{"name":"jill","address":"who knows too"}]'; $array = json_decode($array,true); But what if we want to reverse it and convert an array back to a string: $array ...

What is the method for displaying map tooltips by default rather than on mouseover?

Currently, I have a script set up to display a map with two markers. Whenever I hover over one of the markers, a popup tooltip appears with location information. My question is, how can I make the information appear by default without needing to hover ov ...

A step-by-step guide on integrating vuetify-component into codeceptjs

When attempting to write tests using codecept.js, I am facing difficulties accessing the vuetify components. <v-layout> <v-flex xs7> <v-text-field ref="video1min" v-model="video1min" :rules=" ...

Verifying with VueJS and Jest: How to test if a component's method calls an imported function

I've created a VueJS 2 component that has the following structure: <template> <div> <button @click="onFavorite"> Add to favorites </button> </div> </template> <script> import { tra ...