Build array from another array if some key are identical using JavaScript - javascript

I have an array of data. Some of the key in the array are same. I would like to create a new array based on the key and add the other data.
This is my array
var myObjOne = [
{
"name":"John",
"id":1,
"car":"maruti"
},
{
"name":"John",
"id":2,
"car":"wolks"
},
{
"name":"John",
"id":3,
"car":"bmw"
},
{
"name":"Peter",
"id":4,
"car":"alto"
},
{
"name":"Peter",
"id":5,
"car":"swift"
}
];
I would like to convert the array in to the below format.
var myObj = [
{
"name":"John",
"items": [
{ "id":1, "car":"maruti" },
{ "id":2, "car":"wolks" },
{ "id":3, "car":"bmw" }
]},
{
"name":"Peter",
"items": [
{ "id":4, "car":"alto" },
{ "id":5, "car":"swift" },
]
}
];
I am working on a node environment.

You can create an object using Array#reduce first which maps name with items, and then create the final array by looping over the intermediate map using a for...of loop:
var source = [{"name":"John","id":1,"car":"maruti"},{"name":"John","id":2,"car":"wolks"},{"name":"John","id":3,"car":"bmw"},{"name":"Peter","id":4,"cars":"alto"},{"name":"Peter","id":5,"cars":"swift"}];
const map = source.reduce((acc, {name, ...obj}) => {
if (!acc[name]) {
acc[name] = [];
}
acc[name].push(obj);
return acc;
}, {});
const result = [];
for (let[name, items] of Object.entries(map)) {
result.push({name, items});
}
console.log(result);

Array.reduce is at rescue.This method accepts an accumulator and current
item. Check in the accumulator if there exist an object where the value of name property is John or Peter
var myObjOne = [{
"name": "John",
"id": 1,
"car": "maruti"
},
{
"name": "John",
"id": 2,
"car": "wolks"
},
{
"name": "John",
"id": 3,
"car": "bmw"
},
{
"name": "Peter",
"id": 4,
"car": "alto"
},
{
"name": "Peter",
"id": 5,
"car": "swift"
}
];
var newObj = myObjOne.reduce(function(acc, curr, currIndex) {
// using findIndex to check if there exist an object
// where the value of the name property is John, Peter
// if it exist it will return the index else it will return -1
let ifNameExist = acc.findIndex(function(item) {
return item.name === curr.name;
})
// if -1 then create a object with name and item property and push
// it to the accumulator
if (ifNameExist === -1) {
let nameObj = {};
nameObj.name = curr.name;
nameObj.items = [];
nameObj.items.push({
id: curr.id,
car: curr.car
})
acc.push(nameObj)
} else {
// if such an object already exist then just update the item array
acc[ifNameExist].items.push({
id: curr.id,
car: curr.car
})
}
return acc;
}, []);
console.log(newObj)

Use .reduce to group by name, and use .find inside the reducer to find if the matching name has already been added:
const input=[{"name":"John","id":1,"car":"maruti"},{"name":"John","id":2,"car":"wolks"},{"name":"John","id":3,"car":"bmw"},{"name":"Peter","id":4,"cars":"alto"},{"name":"Peter","id":5,"cars":"swift"}]
const output = input.reduce((a, { name, ...item }) => {
const foundNameObj = a.find(nameObj => nameObj.name === name);
if (foundNameObj) foundNameObj.items.push(item);
else a.push({ name, items: [item] });
return a;
}, []);
console.log(output);

Related

How to create JSON Object in JavaScript?

I have JSON like this :
{
"success":true,
"data":[
{
"id": 1,
"markname":"nama_penduduk",
"markvalue":"Vin Diesel"
},
{
"id": 2,
"markname":"umur_penduduk",
"markvalue":"20 Tahun"
},
{
"id": 3,
"markname":"keperluan_membuat_surat",
"markvalue":"Untuk uji coba surat"
}
]
}
I'm trying to create a JSON like this :
const newJSON = {
nama_penduduk: 'Vin Diesel',
umur_penduduk: '20 Tahun',
keperluan_membuat_surat: 'Untuk uji coba surat'
};
Code :
dataResult.map((value) => {
const markName = value.markname;
const markValue = value.markvalue;
res.status(200).json({
markName: markValue
});
});
Suppose I don't know how many data I have, how do I create this object in JavaScript?
You can use Array.reduce()
const dataResult = [{
"id": 1,
"markname": "nama_penduduk",
"markvalue": "Vin Diesel"
},
{
"id": 2,
"markname": "umur_penduduk",
"markvalue": "20 Tahun"
},
{
"id": 3,
"markname": "keperluan_membuat_surat",
"markvalue": "Untuk uji coba surat"
}
]
const newJSON = dataResult.reduce((acc, cur) => {
acc[cur.markname] = cur.markvalue;
return acc;
}, {});
console.log(newJSON);
Use reduce:
const myObject = dataResult.reduce((acc, curr) => {
curr[acc.markname] = acc.markvalue;
return curr;
}, {});
So yeah, we add acc.markname on the returned object. Pretty self explanatory :)

Assign to object within map

I'd like to assign to an object within an array map
Heres the array of objects I want to add to
const arr = [
{
"key": "Mike",
"ref": 11800
},
{
"key": "Raph",
"ref": 9339
},
{
"key": "Leo",
"ref": 2560
},
]
I want to add add a new property to the object called slug while I loop over it like below. Possibly map is not the right function to use here because ESLINT complains about assigning within the map.
arr.map((item) => {
...item,
item.slug = `${item.key.toLowerCase();}/${String(item.ref)}`
});
.map() returns a new array containing the results of calling provided function for each element, so you should assign it to the new variable:
const arr = [{
"key": "Mike",
"ref": 11800
},
{
"key": "Raph",
"ref": 9339
},
{
"key": "Leo",
"ref": 2560
},
]
const newArr = arr.map(item => ({
...item,
slug: `${item.key.toLowerCase()}/${String(item.ref)}`
}))
console.dir(newArr)
If you want to add something to existing objects within an array you should use a for loop or .forEach():
const arr = [{
"key": "Mike",
"ref": 11800
},
{
"key": "Raph",
"ref": 9339
},
{
"key": "Leo",
"ref": 2560
},
]
arr.forEach(item => {
item.slug = `${item.key.toLowerCase()}/${String(item.ref)}`
})
console.dir(arr)
When mutating an array, or perform operations with side-effects, you should use a for loop or the Array.prototype.forEach method. If you want to perform pure functional operations over an array, then use Array.prototype.filter, Array.prototype.map, etc.
If you want to set a new property on the existing array elements then do this:
const arr = [ { key: "Mike", ref: 11800 }, /*etc*/ ];
for( const e of arr ) {
e.slug = e.key.toLowerCase() + "/" + e.ref.toString();
}
If you want to generate a new array with new members, then do this:
const arr = [ { key: "Mike", ref: 11800 }, /*etc*/ ];
// Note the parentheses within `map` to avoid ambiguous syntax:
const newArr = arr.map( e => ( { slug: e.key.toLowerCase() + "/" + e.ref.toString() } ) );
console.log( newArr ); // [ { slug: "mike/11800" } ]
Alternatively, to copy over all properties and then add new properties use Object.assign:
const arr = [ { key: "Mike", ref: 11800 }, /*etc*/ ];
const newArr = arr.map( e => Object.assign( {}, e, { slug: e.key.toLowerCase() + "/" + e.ref.toString() } ) );
console.log( newArr ); // [ { key: "Mike", ref: 11800, slug: "mike/11800" } ]

Rename unknow key from json array in javascript

I been searching with no success, i would like to iterate over a json object but this have diferent names on keys, below my code
[{
"05115156165165" :{
"name":"John",
"Phone":"515555"
},
"111111111":{
"name":"John",
"Phone":"515555"
}
}]
So basically i need in the following way:
[{
"data" :{
"name":"John",
"Phone":"515555"
},
"data":{
"name":"John",
"Phone":"515555"
}
}]
You can use Object.values to retrieve values for unknwon keys and reduce to transform input array:
let input = [{
"05115156165165" :{
"name":"John",
"Phone":"515555"
},
"111111111":{
"name":"John",
"Phone":"5155557"
}
}];
let result = input.reduce((acc,cur)=> {
Object.values(cur).forEach(
obj => {acc.push({ data: obj });}
)
return acc;
},[]);
console.log(result);
The key is use Object.entries to iterate through all the keys in the object, which in this case it has only 1 that the name is unknown in every object.
const data = [{
"05115156165165": {
"name": "John1",
"Phone": "1111111"
},
"111111111": {
"name": "John2",
"Phone": "2222222"
}
}]
let result = []
data.forEach(d => {
for (const [key, value] of Object.entries(d)) {
result.push({
data: {
name: value.name,
Phone: value.Phone
}
})
}
})
console.log(result)
You can do something like this:
let data = [{
"05115156165165": {
"name": "John1",
"Phone": "1111111"
},
"111111111": {
"name": "John2",
"Phone": "2222222"
}
}]
let result = []
data.forEach(d => {
Object.keys(d).forEach(el => {
result.push({
data: d[el]
})
})
})
console.log(result)

Create JSON Array dynamically from an object

I have an object A as shown below.
var A = {
"1": [ "1_1", "1_2", "1_3" ],
"2": [ "2_1", "2_2" ]
};
Need to build a new array dynamically using js. Suppose
object A key should map to attribute text of Array AA and value should be to children as given below.
var AA = [
{
"text": "1",
"state": "open",
"children": [
{ "text": "1_1" },
{ "text": "1_2" },
{ "text": "1_3" }
]
},
{
"text": "2",
"state": "open",
"children": [
{ "text": "2_1" },
{ "text": "2_2" }
]
}
];
This is my function but its not working as expected. Could someone pls help?
function constructJSONArr() {
var A = {
"1": [ "1_1", "1_2", "1_3" ],
"2": [ "2_1", "2_2" ]
};
for (var key in A) {
var tempArr = [];
tempArr.push(key);
for (var i = 0; i < key.length; i++) {
return {
'text': key,
'state': 'closed',
'children': A[key].map(function(child) {
return {
'text': child
};
})
}
}
}
}
When you return inside a function, the function ends and returns immediately. In your case, the return inside the for loop causes the function to return the 1st key object. To solve this, you need to create the objects and push them into an arr. You can return freely inside Array.map() because each iteration invokes a function.
Fixed solution:
Iterate with for...in. Get the key. Push a new object into arr. Use the key as the text property, the state, and children. To create the children get the array from the original object by the key, and use Array.map() to generate the child objects. Return arr.
var A = {
"1": ["1_1", "1_2", "1_3"],
"2": ["2_1", "2_2"]
};
function constructJSONArr(A) {
var arr = [];
for (var key in A) {
arr.push({
text: key,
state: 'closed',
children: A[key].map(function(t) {
return {
text: t
};
})
});
}
return arr;
}
var result = constructJSONArr(A);
console.log(result);
ESNext solution
Use Object.entries() to get keys and respective values from the object A. Iterate the entries with two nested Array.map() calls. The 1st to create the outer object, and the 2nd to create the children.
const A = {
"1": ["1_1", "1_2", "1_3"],
"2": ["2_1", "2_2"]
};
const constructJSONArr = (obj) =>
Object.entries(obj).map(([text, children]) => ({
text,
state: 'closed',
children: children.map((text) => ({
text
}))
}));
var result = constructJSONArr(A);
console.log(result);
You can use Object.keys() to iterate through the object and Array.map to create the new array.
var A = {
"1": ["1_1", "1_2", "1_3"],
"2": ["2_1", "2_2"]
};
var transformed = Object.keys(A).map(key => {
return {
text: key,
state: "open",
children: A[key].map(value => {
return {
text: value
};
})
};
});
console.log(transformed);

Grouping the elements of an object. (underscore.js)

I have an object as shown below :
[
{"ClientGroupName":"ABC","CompanyName":"AA","ControlGroupName":"1"},
{"ClientGroupName":"ABC","CompanyName":"BB","ControlGroupName":"1"},
{"ClientGroupName":"ABC","CompanyName":"CC","ControlGroupName":"1"},
{"ClientGroupName":"ABC","CompanyName":"DD","ControlGroupName":"2"},
{"ClientGroupName":"ABC","CompanyName":"EE","ControlGroupName":"3"},
{"ClientGroupName":"DEF","CompanyName":"FF","ControlGroupName":"1"},
{"ClientGroupName":"DEF","CompanyName":"GG","ControlGroupName":"1"},
{"ClientGroupName":"DEF","CompanyName":"HH","ControlGroupName":"2"}
]
I need to group it like this :
[
[
[
{"ClientGroupName":"ABC","CompanyName":"AA","ControlGroupName":"1"},
{"ClientGroupName":"ABC","CompanyName":"BB","ControlGroupName":"1"},
{"ClientGroupName":"ABC","CompanyName":"CC","ControlGroupName":"1"}
],
[{"ClientGroupName":"ABC","CompanyName":"DD","ControlGroupName":"2"}],
[{"ClientGroupName":"ABC","CompanyName":"EE","ControlGroupName":"3"}]
],
[
[
{"ClientGroupName":"DEF","CompanyName":"FF","ControlGroupName":"1"},
{"ClientGroupName":"DEF","CompanyName":"GG","ControlGroupName":"1"}
],
[{"ClientGroupName":"DEF","CompanyName":"HH","ControlGroupName":"2"}]
]
]
I am using underscore.js to group the elements in the object.
$scope.InitController = function () {
ClientGroupService.GetClientGroupList().then(function (response) {
$scope.groupByTwoFields = [];
$scope.groupByTwoFields = _.groupBy(response.data, function (obj) {
return obj.ClientGroupName + '|' + obj.ControlGroupName;
});
.....
});
};
The output from the above code looks like :
[
[
{"ClientGroupName":"ABC","CompanyName":"AA","ControlGroupName":"1"},
{"ClientGroupName":"ABC","CompanyName":"BB","ControlGroupName":"1"},
{"ClientGroupName":"ABC","CompanyName":"CC","ControlGroupName":"1"}
],
[{"ClientGroupName":"ABC","CompanyName":"DD","ControlGroupName":"2"}],
[{"ClientGroupName":"ABC","CompanyName":"EE","ControlGroupName":"3"}],
[
{"ClientGroupName":"DEF","CompanyName":"FF","ControlGroupName":"1"},
{"ClientGroupName":"DEF","CompanyName":"GG","ControlGroupName":"1"}
],
[{"ClientGroupName":"DEF","CompanyName":"HH","ControlGroupName":"2"}]
]
What do I need to do in order to get the desired output as shown above.
Your code producing the output in the below shown form :
[
[
{"ClientGroupName":"ABC","CompanyName":"AA","ControlGroupName":"1"},
{"ClientGroupName":"ABC","CompanyName":"BB","ControlGroupName":"1"},
{"ClientGroupName":"ABC","CompanyName":"CC","ControlGroupName":"1"},
{"ClientGroupName":"ABC","CompanyName":"DD","ControlGroupName":"2"},
{"ClientGroupName":"ABC","CompanyName":"EE","ControlGroupName":"3"}
],
[
{"ClientGroupName":"DEF","CompanyName":"FF","ControlGroupName":"1"},
{"ClientGroupName":"DEF","CompanyName":"GG","ControlGroupName":"1"},
{"ClientGroupName":"DEF","CompanyName":"HH","ControlGroupName":"2"}]
]
Here's a very simple function to do it in vanilla JavaScript, it takes two arguments:
arr The array containing the objects that you want to group.
properties An array of strings with the names of the properties you want to group the objects by, ordered by priority (objects will be ordered by the first property in the array, then the second, etc).
function groupByProperties(arr, properties) {
const groups = {
root: {
array: [],
children: {}
}
};
arr.forEach(obj => {
let group = groups.root;
properties.forEach(propertyKey => {
const property = obj[propertyKey];
if (!group.children.hasOwnProperty(property)) {
const child = {
array: [],
children: {}
}
group.array.push(child.array);
group.children[property] = child;
}
group = group.children[property];
});
group.array.push(obj);
});
return groups.root.array;
}
You would use it as follows:
let data = [
{"ClientGroupName":"ABC","CompanyName":"AA","ControlGroupName":"1"},
{"ClientGroupName":"ABC","CompanyName":"BB","ControlGroupName":"1"},
{"ClientGroupName":"ABC","CompanyName":"CC","ControlGroupName":"1"},
{"ClientGroupName":"ABC","CompanyName":"DD","ControlGroupName":"2"},
{"ClientGroupName":"ABC","CompanyName":"EE","ControlGroupName":"3"},
{"ClientGroupName":"DEF","CompanyName":"FF","ControlGroupName":"1"},
{"ClientGroupName":"DEF","CompanyName":"GG","ControlGroupName":"1"},
{"ClientGroupName":"DEF","CompanyName":"HH","ControlGroupName":"2"}
];
console.log(groupByProperties(data, ["ClientGroupName", "ControlGroupName"]));
i did it with just vanillaJS in case the answer above didn't work for you:
var data = [
{"ClientGroupName":"ABC","CompanyName":"AA","ControlGroupName":"1"},
{"ClientGroupName":"ABC","CompanyName":"BB","ControlGroupName":"1"},
{"ClientGroupName":"ABC","CompanyName":"CC","ControlGroupName":"1"},
{"ClientGroupName":"ABC","CompanyName":"DD","ControlGroupName":"2"},
{"ClientGroupName":"ABC","CompanyName":"EE","ControlGroupName":"3"},
{"ClientGroupName":"DEF","CompanyName":"FF","ControlGroupName":"1"},
{"ClientGroupName":"DEF","CompanyName":"GG","ControlGroupName":"1"},
{"ClientGroupName":"DEF","CompanyName":"HH","ControlGroupName":"2"}
];
var ClientGroupNames = [];
data.forEach(function(o){
if(ClientGroupNames.indexOf(o.ClientGroupName) < 0){
ClientGroupNames.push(o.ClientGroupName);
}
});
var result = ClientGroupNames.map(function(name){
return data.filter(function(comp){
return comp.ClientGroupName == name ? true : false;
})
}).map(function(grp){
var groupNames = [];
grp.forEach(function(company){
if(groupNames.indexOf(company.ControlGroupName) < 0)
groupNames.push(company.ControlGroupName);
})
return groupNames.map(function(name){
return grp.filter(function(gp){
return gp.ControlGroupName == name ? true : false;
})
})
})
_.groupBy doesn't return an array, it returns an object.
var data = [{
"ClientGroupName": "ABC",
"CompanyName": "AA",
"ControlGroupName": "1"
}, {
"ClientGroupName": "ABC",
"CompanyName": "BB",
"ControlGroupName": "1"
}, {
"ClientGroupName": "ABC",
"CompanyName": "CC",
"ControlGroupName": "1"
}, {
"ClientGroupName": "ABC",
"CompanyName": "DD",
"ControlGroupName": "2"
}, {
"ClientGroupName": "ABC",
"CompanyName": "EE",
"ControlGroupName": "3"
}, {
"ClientGroupName": "DEF",
"CompanyName": "FF",
"ControlGroupName": "1"
}, {
"ClientGroupName": "DEF",
"CompanyName": "GG",
"ControlGroupName": "1"
}, {
"ClientGroupName": "DEF",
"CompanyName": "HH",
"ControlGroupName": "2"
}];
var obj = _.groupBy(data,function (obj) {
return obj.ClientGroupName;
}); // groupBy returns an object, not a array
var result = Object.keys(obj).map(function (key) { return obj[key]; }); // this converts the object to an array
_.each(result,function(obj,index){ // loop through each item in the array
var _obj = _.groupBy(obj,function(obj2){
return obj2.ControlGroupName;
}); // group it by the ControlBroupName and convert it to a array
result[index] = Object.keys(_obj).map(function (key) { return _obj[key]; });
});
console.log("result:\n", result);
You have to groupBy twice:
result = _(data).groupBy('ClientGroupName').map(g =>
_.values(_.groupBy(g, 'ControlGroupName'))
).value()

Categories