Issue adding key value pair to javascript object from an array - javascript

I have an object like this
let obj = {
"apple": {
"color": "red",
},
"banana": {
"color": "yellow"
}
}
I am getting an array of objects of this form
let arr = [
{
"count": "9904",
"fruit": "apple",
"type": "typea"
},
{
"count": "7142",
"fruit": "banana",
"type": "typeb"
},
{
"count": "4121",
"fruit": "apple",
"type": "typec"
}
]
I want to combine these two so that each item in objcan have variable no of properties so that final output look something like this
{
"apple": {
"color": "red",
"typea": "9904",
"typec": "4121"
},
"banana": {
"color": "yellow",
"typeb": "7142"
}
}
I tried running the array through a for loop but when I try to use the dynamic values in keys it shows error
for (let item of arr){
obj[item.fruit] = {...obj[item.fruit], item.type: item.count}
}
If instead of item.type I put some static value like "count" it works but I can't figure out how to use dynamic value
Can anyone suggest me what is the best way to accomplish this?

You should use computed property names with square brackets.
let obj = {
"apple": {
"color": "red",
},
"banana": {
"color": "yellow"
}
}
let arr = [
{
"count": "9904",
"fruit": "apple",
"type": "typea"
},
{
"count": "7142",
"fruit": "banana",
"type": "typeb"
},
{
"count": "4121",
"fruit": "apple",
"type": "typec"
}
]
for (let item of arr){
obj[item.fruit] = {...obj[item.fruit], [item.type]: item.count}
}
console.log(obj);

Here's a verbose and explicit example of how you can do this using Array.prototype.reduce.
(Note that MDN will be down for maintenance for up to an hour at some point today.)
const
obj = { apple:{color:"red"}, banana:{color:"yellow"} },
arr = [
{ fruit: "apple", type: "typeA", count: 9 },
{ fruit: "banana", type: "typeB", count: 7 },
{ fruit: "apple", type: "typeC", count: 4 }
];
arr.reduce( (theObj, current) => {
// Reduce loops through the array, updating theObj for each item
const
fruitName = current.fruit, // Gets fruit name
fruitObjInObj = theObj[fruitName], // Gets fruit obj
type = current.type, // Gets type from current item
count = current.count; // Gets count from current item
fruitObjInObj[type] = count; // Adds property to fruit obj
return theObj; // Gives theObj back to `reduce` for next loop
}, obj); // Tells `reduce` to use obj as theObj on first loop
console.log(obj);

Related

How to replace object props inside array with other object

I have an array of objects like this one:
let arr1 = [{
"ref": 1,
"index": "300",
"data": {
"id": 10,
"status": {
"code": "red"
}
}
}, {
"ref": 2,
"index": "301",
"data": {
"id": 20,
"status": {
"code": "blue"
}
}
}];
I want to replace the status.code by the one given in this other array of objects:
let arr2 = [{
"id": 10,
"content": {
"name": "green"
}
}, {
"id": 20,
"content": {
"name": "yellow"
}
}];
My idea is to map the first array and the use the find function (or filter) to loop the second array and when the ID's match change the values but I'm missing something, how can i do this the most optimized for performance and readability way?
let res: any[];
res = arr2.map((x: any) =>
arr1.find((y: any) =>
(y.data.id === x.id) ? 'logic if match' : 'return'
));
I would first change the format of arr2 in such a way that it is easier to access in such a format: (If you can easily change how you get this data, it would be better I think. Otherwise, transform the data as below.)
const idStatusCodeMap = {
"10": "green",
"20": "yellow"
}
We do this so we can just look if there is idStatusCodeMap[10] or idStatusCodeMap[anyId]. This makes it possible that you only loop through arr1, not a nested loop for both arr1 and arr2.
Then, loop through arr1 and replace the colours if necessary. If suppose, a new colour is not found on idStatusCodeMap, such as for id = 30, then don't do anything for that.
let arr1 = [{
"ref": 1,
"index": "300",
"data": {
"id": 10,
"status": {
"code": "red"
}
}
}, {
"ref": 2,
"index": "301",
"data": {
"id": 20,
"status": {
"code": "blue"
}
}
}];
let arr2 = [{
"id": 10,
"content": {
"name": "green"
}
}, {
"id": 20,
"content": {
"name": "yellow"
}
}];
let idStatusCodeMap = {}
//transpiling arr2 to more performant hashMap
arr2.forEach(item => {
idStatusCodeMap[item.id] = item.content.name;
})
console.log(idStatusCodeMap);
arr1 = arr1.map(item => {
//if the id of an item in arr1 is found in code map, replace it with new value.
//if not found, it will skip.
if(idStatusCodeMap[item.data.id]) {
item.data.status.code = idStatusCodeMap[item.data.id]
}
return item;
})
console.log(arr1);

How to .map correctly this array of objects?

I'm not sure what I'm doing wrong but I would like to map an array of objects. This array of objects it's dynamic, this means sometimes it has 4 objects and sometimes 20, so I need to make sure it will work no matters how many entries it has:
var obj = [
{
"key": "one",
"value": "something"
},
{
"key": "two",
"value": "random"
},
{
"key": "blue",
"value": "chicken"
},
{
"key": "orange",
"value": "sportsman"
}
];
I need to pass this objects into one to send it through a POST call that should match this format:
form: {
'one': 'something',
'two': 'random',
'blue': 'chicken',
'orange': 'sportsman'
}
I can access to item.value but IDK why I can't item.key:
var obj = [
{
"key": "one",
"value": "something"
},
{
"key": "two",
"value": "random"
},
{
"key": "blue",
"value": "chicken"
},
{
"key": "orange",
"value": "sportsman"
}
];
var combined = obj.map(function combined(item) {
return {
item.key: item.value
};
})
console.log(combined);
Any ideas? Thanks.
You shouldn't return an object from your callback function. Return an array of the key and value, then use Object.fromEntries() to turn this into a single object with those keys and values.
var obj = [{
"key": "one",
"value": "something"
},
{
"key": "two",
"value": "random"
},
{
"key": "blue",
"value": "chicken"
},
{
"key": "orange",
"value": "sportsman"
}
];
var combined = Object.fromEntries(obj.map(item => [item.key, item.value]));
console.log(combined);
1) You can't use a map here because the map will return a new array. You can achieve this result using reduce
var obj = [
{
key: "one",
value: "something",
},
{
key: "two",
value: "random",
},
{
key: "blue",
value: "chicken",
},
{
key: "orange",
value: "sportsman",
},
];
const result = obj.reduce((acc, curr) => {
const { key, value } = curr;
acc[key] = value;
return acc;
}, {});
console.log(result);
2) You can also do this using for..of loop
var obj = [{
key: "one",
value: "something",
},
{
key: "two",
value: "random",
},
{
key: "blue",
value: "chicken",
},
{
key: "orange",
value: "sportsman",
},
];
const result = {};
for (let o of obj) {
result[o.key] = o.value;
}
console.log(result);

How to group JSON data on the base of attribute value in different variables?

I want to group JSON data by color as an example:
blue colors will be collected in variable "a"
green colors will be collected in variable "b"
red colors will be collected in variable "c"
How can I do that, My JSON data is here:
var data = [{
"name": "2",
"number": "222",
"day": 20,
"color": "red"
},
{
"name": "3",
"number": "333",
"day": 19,
"color": "green"
},
{
"name": "5",
"number": "333",
"day": 19,
"color": "blue"
}];
console.log(data.reduce(function(result, current) {
result[current.color] = result[current.color] || [];
result[current.color].push(current);
return result;
}, {}));
consequently, all blue, green, and red values ​​in the data are collected in different variables in series.
I think in reduce, you must grouping item by color, and then set variable a,b,c:
const reducedData = data.reduce((acc, rec) => {
if (acc.hasOwnProperty(rec.color)){
acc[rec.color].push(rec)
}
else {
acc = {...acc, [rec.color]: [rec]}
}
return {...acc}
},{})
const a = reducedData.blue
const b = reducedData.green
const c = reducedData.red
See full example in playground: https://jscomplete.com/playground/s507178

How can I transform an array of objects into a new array of objects grouped by property?

Please see my Fiddle which includes all the code that follows.
My apologies if this question has been answered before. I found similar questions on here about grouping by property, but I did not find an example where the result was still an array of objects.
I'm starting with this data format:
const originalData = [
{
"groupId": 0,
"color": "red",
"shape": "circle"
},
{
"groupId": 1,
"color": "green",
"shape": "square"
},
{
"groupId": 1,
"color": "orange",
"shape": "hexagon"
},
{
"groupId": 1,
"color": "purple",
"shape": "triangle"
},
{
"groupId": 2,
"color": "aqua",
"shape": "diamond"
},
{
"groupId": 2,
"color": "blue",
"shape": "trapezoid"
}
];
And I would like to transform it into a new array of objects, grouped by groupId property value:
const desiredData = [
{
"groupId": 0,
"items": [
{
"color": "red",
"shape": "circle"
}
]
},
{
"groupId": 1,
"items": [
{
"color": "green",
"shape": "square"
},
{
"color": "orange",
"shape": "hexagon"
},
{
"color": "purple",
"shape": "triangle"
}
]
},
{
"groupId": 2,
"items": [
{
"color": "aqua",
"shape": "diamond"
},
{
"color": "blue",
"shape": "trapezoid"
}
]
}
];
This reduce function (which I found on MDN) is the closest I was able to come to transforming my data. My experience with transforming data in Javascript is limited, and I am not sure how to add fields (like group) during the transformation process. Also, the result is an object, not an array of objects.
const actualFormattedData = originalData.reduce((acc, obj) => {
let key = obj['groupId'];
if (!acc[key]) {
acc[key] = [];
}
acc[key].push(obj);
return acc;
}, {});
Output from the reduce function:
{
"0": [
{
"groupId": 0,
"color": "red",
"shape": "circle"
}
],
"1": [
{
"groupId": 1,
"color": "green",
"shape": "square"
},
{
"groupId": 1,
"color": "orange",
"shape": "hexagon"
},
{
"groupId": 1,
"color": "purple",
"shape": "triangle"
}
],
"2": [
{
"groupId": 2,
"color": "aqua",
"shape": "diamond"
},
{
"groupId": 2,
"color": "blue",
"shape": "trapezoid"
}
]
}
The ultimate goal is to map the array of objects in React. I know I can use Object.entries and array indices to achieve a similar result with actualFormattedData as-is, but it would be ideal if I could first make actualFormattedData look exactly like desiredData.
This should work:
const dict = originalData.reduce((acc, obj) => {
let groupId = obj['groupId'];
delete obj.groupId;
if (!acc[groupId]) {
acc[groupId] = { // here is where we add the fields you wanted
groupId,
items: []
};
}
acc[groupId].items.push(obj);
return acc;
}, {});
// turn this into an array, just getting the values of the fields in the dictionary
const actualFormattedData = Object.values(dict);
Here is your fiddle solution
https://jsfiddle.net/07n9ks86/
and the crucial code for it (n2):
const formattedData = originalData.reduce((acc, curr) => {
console.log(acc)
const index = acc.findIndex(x => x.group === curr.group);
if (index > 0) {
acc[index] = {
...acc[index],
items: [...acc[index].items,
{
'color': curr.color,
'shape': curr.shape
}
]
}
} else {
acc.push({
group: curr.group,
items: [{
'color': curr.color,
'shape': curr.shape
}]
})
}
return acc;
}, []);
A simple solution can be achieved with a single call to Array#reduce(), as detailed in the code snippet below.
Just a note that this solution emphasises simplicity over efficiency, and would tend to not be suitable for very large input arrays:
const originalData=[{groupId:0,color:"red",shape:"circle"},{groupId:1,color:"green",shape:"square"},{groupId:1,color:"orange",shape:"hexagon"},{groupId:1,color:"purple",shape:"triangle"},{groupId:2,color:"aqua",shape:"diamond"},{groupId:2,color:"blue",shape:"trapezoid"}];
/* Use reduce to iterate and transform originalData array to desired result */
const desiredData = originalData.reduce((result, item) => {
/* The group item to add from this iteration */
const groupItem = { color : item.color, shape : item.shape };
/* Search for item that already exists with matching group id */
const existingGroup = result.find(resultItem => resultItem.groupId === item.groupId);
if(existingGroup) {
/* Add item to group if found */
existingGroup.items.push(groupItem);
}
else {
/* Add group with item if not group found */
result.push({
groupId : item.groupId,
items : [ groupItem ]
});
}
return result;
}, []);
console.log(desiredData);
Hope that helps!
Another simplest method to group by property name can be using lodash.
let groupedData = _.groupBy(rawData, dataObj => dataObj.propertyToGroupBy)
Where groupedData is the result you are looking for, rawData is the original data and propertyToGroupBy is the property of the object with which you want to group.
You can check this answer.
Here is an easy to understand solution:
const originalData = [
{
"groupId": 0,
"color": "red",
"shape": "circle"
},
{
"groupId": 1,
"color": "green",
"shape": "square"
},
{
"groupId": 1,
"color": "orange",
"shape": "hexagon"
},
{
"groupId": 1,
"color": "purple",
"shape": "triangle"
},
{
"groupId": 2,
"color": "aqua",
"shape": "diamond"
},
{
"groupId": 2,
"color": "blue",
"shape": "trapezoid"
}
];
const data = [];
const dataObjIndex = id=>{
for(let i=0,l=data.length; i<l; i++){
if(data[i].groupId === id){
return i;
}
}
return -1;
}
originalData.forEach(o=>{
let i = dataObjIndex(o.groupId);
if(i === -1){
i = data.length; data.push({groupId:o.groupId, items:[]});
}
data[i].items.push({color:o.color, shape:o.shape});
});
console.log(data);

Loop through array and get objects with a certain string

ex:
{
"data": [
{
"name": "grape",
"color": "purple"
},
{
"name": "apple",
"color": "green"
}
]
}
Let's say I ONLY want to get objects with the color of purple. How would I do this?
Something like this? You can use JavaScript's Array.filter().
const obj = {
"data": [
{
"name": "grape",
"color": "purple"
},
{
"name": "apple",
"color": "green"
}
]
};
const result = obj.data.filter(element => element.color === 'purple');
console.log(result);
This filters through the array and returns a list of objects with the color of purple.

Categories