I have an object of arrays, I want to create individual objects from those array values,
"SUMMARY_TABLE": {
"PRODUCT_CODE": [
123,
123,
123,
123,
123
],
"TYPE": [
"CURRENT",
"OPTIMAL",
"MINIMUM",
"MAXIMUM",
"FUTURE"
],
"LOT_SIZE": [
268.0,
268.0,
268.0,
268.0,
500.0
]}
above is the response Im getting. I want to create 5 individual objects from this data like
{
"product_code": 123,
"type": "current",
"lot_size" : 268
}
similarly using values in the arrays at other indexes.
I am trying this but it is not giving me the result I need. k contains the key name and array of values, like ['Product_Code', Arr(5)]
const data = Object.entries(selectedProductDetails.SUMMARY_TABLE).map(
(k, v) => {
let obj = {};
return {
...obj, k: k[i++]
}
});
I would appreciate any help in this.
You can use .map and create a new object for each element.
Here's an example:
const summaryTable = {
"PRODUCT_CODE": [
123,
123,
123,
123,
123
],
"TYPE": [
"CURRENT",
"OPTIMAL",
"MINIMUM",
"MAXIMUM",
"FUTURE"
],
"LOT_SIZE": [
268.0,
268.0,
268.0,
268.0,
500.0
]
};
const individualObjects = summaryTable.PRODUCT_CODE.map((productCode, index) => {
return {
product_code: productCode,
type: summaryTable.TYPE[index].toLowerCase(),
lot_size: summaryTable.LOT_SIZE[index]
}
});
console.log(individualObjects);
You can iterate over all the values of one of the arrays stored in table to be able to get the index, then iterate over the keys & values of table to get every property. This makes it so if table changes, you don't need to modify this code.
const table = {
PRODUCT_CODE: [123, 123, 123, 123, 123],
TYPE: ["CURRENT", "OPTIMAL", "MINIMUM", "MAXIMUM", "FUTURE"],
LOT_SIZE: [268.0, 268.0, 268.0, 268.0, 500.0],
};
const entries = Object.entries(table);
const data = table.TYPE.map((_, i) => entries.reduce((acc, [key, value]) => {
acc[key] = value[i];
if (key === "TYPE") acc[key] = value[i].toLowerCase(); // if you need this, keep it
return acc;
}, {}));
console.log(data);
Related
Given the following object, how can I loop through this object inorder to obtain both keys and values but only for the following keys:
"myName": "Demo"
"active": "Y"
"myCode": "123456789"
"myType": 1
let a = {
"values": {
"myName": "Demo",
"active": "Y",
"myCode": "123456789",
"myType": 1,
"myGroups": [
{
"myGroupName": "Group 1",
"myTypes": [
{
"myTypeName": "323232",
"myTypeId": "1"
}
]
},
{
"myGroupName": "Group 2",
"myTypes": [
{
"myTypeName": "523232",
"myTypeId": "2"
}
]
}
]
}
}
I have tried:
for (const [key, value] of Object.entries(a.values)) {
console.log(`${key}: ${value}`);
For}
but this will return all keys with their values.
You can use a dictionary (array) to contain the keys you want to extract the properties for, and then reduce over the values with Object.entries to produce a new object matching only those entries included in the dictionary.
let a = {
"values": {
"myName": "Demo",
"active": "Y",
"myCode": "123456789",
"myType": 1,
"myGroups": [{
"myGroupName": "Group 1",
"myTypes": [{
"myTypeName": "323232",
"myTypeId": "1"
}]
},
{
"myGroupName": "Group 2",
"myTypes": [{
"myTypeName": "523232",
"myTypeId": "2"
}]
}
]
}
}
const arr = [ 'myName', 'active', 'myCode', 'myType' ];
const out = Object.entries(a.values).reduce((acc, [key, value]) => {
if (arr.includes(key)) acc[key] = value;
return acc;
}, {});
console.log(out);
The best answer would be to set up an array of the desired keys and then iterate over that array instead of an array of the original object's entries. This is how you would achieve that:
let a = {
values: {
myName: "Demo",
active: "Y",
myCode: "123456789",
myType: 1,
myGroups: [{
myGroupName: "Group 1",
myTypes: [{
myTypeName: "323232",
myTypeId: "1"
}]
}, {
myGroupName: "Group 2",
myTypes: [{
myTypeName: "523232",
myTypeId: "2"
}]
}]
}
};
const keys = ['myName', 'active', 'myCode', 'myType'];
const cherryPick = (obj, keys) => keys.reduce((a,c) => (a[c] = obj[c], a), {});
console.log(cherryPick(a.values, keys));
The above example will work for many provided keys. If a key does not exist in the supplied object, its value will be undefined. If you want to only keep properties which have values, simply add an optional filter to the cherryPick() function, like this:
let test = {
a: 1,
b: 2
};
const keys = ['a', 'b', 'c'];
const cherryPick = (obj, keys, filter = 0) => keys.filter(key => filter ? obj[key] : 1).reduce((acc,key) => (acc[key] = obj[key], acc), {});
console.log('STORE undefined :: cherryPick(test, keys)', cherryPick(test, keys));
console.log('FILTER undefined :: cherryPick(test, keys, 1)', cherryPick(test, keys, true));
/* Ignore this */ .as-console-wrapper { min-height: 100%; }
I have this array of nested objects and arrays:
const myArr = [
{
workoutName: "workout1",
exercises: [
{
exerciseName: "Bench Press",
sets: [
{
// some props and vals
},
]
},
{
exerciseName: "Deadlift",
sets: [
{
// some props and vals
},
]
},
{
exerciseName: "Squat",
sets: [
{
// some props and vals
},
]
},
// more exercises
]
}
]
const compareVal = "Deadlift";
const mySetObj = {//some data}
I want to iterate through the exercises array of objects and compare the exerciseName value for each object with the compareVal for a match. If it does match, I want to be able to add myObj as a value to that object's setsarray. Each of the exerciseName values are unique, so it would not be necessary to iterate through all of the exercises after finding a match.
Is there a way I can achieve this elegantly?
Seems like an array find method would be sufficient. Note that, in this solution, we use a forEach loop on the myArr array since it seems you might want to do this for each routine.
myArr.forEach(routine => {
const ex = routine.exercises.find(e => e.exerciseName === compareVal);
ex.sets.push(mySetObj);
})
Update: Since you just need this for myArr[0], this can be simplified as follows:
const ex = myArr[0].exercises.find(e => e.exerciseName === compareVal);
ex.sets.push(mySetObj);
And here it is working:
const myArr = [
{
workoutName: "workout1",
exercises: [
{
exerciseName: "Bench Press",
sets: [
{
// some props and vals
},
]
},
{
exerciseName: "Deadlift",
sets: [
{
// some props and vals
},
]
},
{
exerciseName: "Squat",
sets: [
{
// some props and vals
},
]
},
// more exercises
]
}
]
const compareVal = "Deadlift";
const mySetObj = { some: "data" };
const ex = myArr[0].exercises.find(e => e.exerciseName === compareVal);
ex.sets.push(mySetObj);
console.log(myArr);
Having an array of objects like this:
[{"event_id":1,"person":"John"},
{"event_id":2,"person":"John"},
{"event_id":3,"person":"Mike"},
{"event_id":1,"person":"Mike"},
{"event_id":1,"person":"Anna"},
{"event_id":3,"person":"Anna"}]
the wanted result should combine them based on the event_id and show them in a table structure like this:
1 John, Mike, Ana
2 John
3 Mike, Anna
Each row represents an event and the rows contains the people who participated in that event.
I don't know how do to this in JavaScript. Any suggestions?
You can use reduce:
const data = [
{ event_id: 1, person: 'John' },
{ event_id: 2, person: 'John' },
{ event_id: 3, person: 'Mike' },
{ event_id: 1, person: 'Mike' },
{ event_id: 1, person: 'Anna' },
{ event_id: 3, person: 'Anna' },
];
const result = data.reduce(
(acc, val) => ({
...acc,
[val.event_id]: acc[val.event_id] ? [...acc[val.event_id], val.person] : [val.person],
}),
{},
);
console.log(result);
You can use a Map with .reduce() to first group your objects, where the event_id is the key in the map, and the value is an array of accumulated person values for the same event_id values. You can then use Array.from() to map each [key, value] entry to a string of HTML for the table rows and data. You can then add this string to your HTML like so:
const arr = [{"event_id":1,"person":"John"},
{"event_id":2,"person":"John"},
{"event_id":3,"person":"Mike"},
{"event_id":1,"person":"Mike"},
{"event_id":1,"person":"Anna"},
{"event_id":3,"person":"Anna"}];
const table = `
<table>
${Array.from(
arr.reduce((m, {event_id:id, person}) => m.set(id, [...(m.get(id) || []), person]), new Map),
([key, arr]) => `<tr><td>${key}</td><td>${arr.join(', ')}</td></tr>`
).join('')}
</table>
`;
document.body.innerHTML = table;
I recommend you to use Map data type.
Map is a collection of keyed data items, just like an Object. But the
main difference is that Map allows keys of any type.
First of all we iterate on Array of Objects, then we check if there is any event_id in Map we push Object.person to the value of event_id entry :
const listOfObjects = [
{ "event_id": 1, "person": "John" },
{ "event_id": 2, "person": "John" },
{ "event_id": 3, "person": "Mike" },
{ "event_id": 1, "person": "Mike" },
{ "event_id": 1, "person": "Anna" },
{ "event_id": 3, "person": "Anna" }];
let eventIdCollection = new Map();
listOfObjects.forEach(obj => {
if (eventIdCollection.has(obj.event_id)) {
let persons = eventIdCollection.get(obj.event_id);
persons.push(obj.person);
eventIdCollection.set(obj.event_id, persons);
}
else {
eventIdCollection.set(obj.event_id, [obj.person]);
}
});
the result is Map of event_id to Array of persons.
I would like to use lodash to generete object from array of arrays. I use for it lodash.zipObject method and map. But it is not 1:1 what I would like to generate:
Input:
"rows": [
[
"stravi/aa",
"202001",
"59",
"51",
"2558.98",
"0.5358894453719162",
"1.9204668112983725",
"140",
"2.3466309084813943"
],
[
"stravi/ab",
"202003",
"3591",
"349",
"2246.09",
"0.41838214",
"3.57603358",
"50",
"4.82115474"
],
[
"stravi/ac",
"202007",
"3354",
"25",
"1975.76",
"0.74220667708",
"1.12321555541",
"11",
"0.9324532454"
]
]
dictionary: ['source', 'sessions', 'adClicks', 'adCost', 'CPC', 'CTR', 'goalCompletionsAll', 'goalConversionRateAll' ], [action.yearReportData]
output:
{
source: ['stravi/aa', 'stravi/ab', 'stravi/ac'],
sessions: ['202001', '202003', '202007']
...
}
I would like to use lodash, and I try by:
lodash.map(rows, arr =>
lodash.zipObject(['source', 'sessions', 'adClicks', 'adCost', 'CPC', 'CTR', 'goalCompletionsAll', 'goalConversionRateAll'], arr))
But is not correct... I received multiple object. I would like to have one object with all data. Like my example.
Unzip the rows to transpose the sub-arrays, and then use zip object:
const { flow, unzip, zipObject } = _
const fn = flow(
unzip,
arr => zipObject(['source', 'sessions', 'adClicks', 'adCost', 'CPC', 'CTR', 'goalCompletionsAll', 'goalConversionRateAll'], arr)
)
const rows = [["stravi/aa","202001","59","51","2558.98","0.5358894453719162","1.9204668112983725","140","2.3466309084813943"],["stravi/ab","202003","3591","349","2246.09","0.41838214","3.57603358","50","4.82115474"],["stravi/ac","202007","3354","25","1975.76","0.74220667708","1.12321555541","11","0.9324532454"]]
const result = fn(rows)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
why use third-party library, if may easy do it like so
let result = rows.reduce((obj, arr) => {
arr.forEach((item, i) => {
if (!obj[dictionary[i]]) {
obj[dictionary[i]] = [];
}
obj[dictionary[i]].push(item);
})
return obj;
}, {});
You need a reducer instead of map. Map just transform each elements that is why you get multiple elements.
I would use plain JS for this one. It will look like this:
const rows = [
[
'stravi/aa',
'202001',
'59',
'51',
'2558.98',
'0.5358894453719162',
'1.9204668112983725',
'140',
'2.3466309084813943',
],
[
'stravi/ab',
'202003',
'3591',
'349',
'2246.09',
'0.41838214',
'3.57603358',
'50',
'4.82115474',
],
[
'stravi/ac',
'202007',
'3354',
'25',
'1975.76',
'0.74220667708',
'1.12321555541',
'11',
'0.9324532454',
],
];
const keys = [
'source',
'sessions',
'adClicks',
'adCost',
'CPC',
'CTR',
'goalCompletionsAll',
'goalConversionRateAll',
'missingFieldName',
];
const initialAcc = keys.reduce((acc, cur) => {
acc[cur] = [];
return acc;
}, {});
const resultAcc = rows.reduce((acc, cur) => {
cur.forEach((value, index) => acc[keys[index]].push(value));
return acc;
}, initialAcc);
console.log(resultAcc);
I have an array which has some objects and one of the propery of the object can have dupes viz. Account. Now i want to convert this array to map with key having Account's property value and the corresponding dupes should be stored as an array to that key in the map.
let arr = [];
arr.push({'Key':'1','Record':{'Account':'a','data':'A1'}});
arr.push({'Key':'2','Record':{'Account':'b','data':'123'}});
arr.push({'Key':'3','Record':{'Account':'a','data':'A2'}});
arr.push({'Key':'4','Record':{'Account':'a','data':'A3'}});
arr.push({'Key':'5','Record':{'Account':'c','data':'123'}});
const accIdMap= arr.reduce((map,obj) => (map[obj.Record.Account] = obj,map), {});
console.log(arr);
console.log(accIdMap);
So as of now the accIdMap just gets a one to one key-value mapping which is the last one pushed in the array i.e 4 but i want that the output map should have value as an array where ever the keys were duplicated. I tried reduction but that eliminates the duplicate values but i want the duplicate values as an corresponding array.
For example
As is output
{
"a": {
"Key": "4",
"Record": {
"Account": "a",
"data": "A3"
}
},
"b": {
"Key": "2",
"Record": {
"Account": "b",
"data": "123"
}
},
"c": {
"Key": "5",
"Record": {
"Account": "c",
"data": "123"
}
}
}
Desired OutPut (the keys which were duplicated should have the values added as an array)
{
"a": [{"Key": "4","Record": {"Account": "a","data": "A3"}},{
"Key": "3",
"Record": {
"Account": "a",
"data": "A2"
}
},{
"Key": "1",
"Record": {
"Account": "a",
"data": "A1"
}
}],
"b": {
"Key": "2",
"Record": {
"Account": "b",
"data": "123"
}
},
"c": {
"Key": "5",
"Record": {
"Account": "c",
"data": "123"
}
}
}
You can use reduce like this:
Check if the accumulator already has key with current a.Record.Account. If yes, push the current item in context to it. Else, add a.Record.Account as a key and then push the item to it.
const input = [{'Key':'1','Record':{'Account':'a','data':'A1'}},
{'Key':'2','Record':{'Account':'b','data':'123'}},
{'Key':'3','Record':{'Account':'a','data':'A2'}},
{'Key':'4','Record':{'Account':'a','data':'A3'}},
{'Key':'5','Record':{'Account':'c','data':'123'}}]
const output = input.reduce((acc, a) =>
((acc[a.Record.Account] = acc[a.Record.Account] || []).push(a), acc), {})
console.log(output);
Doing a check in the reduce function if the value exists already, then based on that you can do the following. If the Account already exists then check if the map has a array on that Account's key. If not create an array with the existing element and the current one by creating an empty array and pushing to that. If it is an array then just push to it. If the Account key doesn't exist then just set the value as the obj.
Update: Reordered the initialization of const m and added comment on code.
let arr = [];
arr.push({'Key':'1','Record':{'Account':'a','data':'A1'}});
arr.push({'Key':'2','Record':{'Account':'b','data':'123'}});
arr.push({'Key':'3','Record':{'Account':'a','data':'A2'}});
arr.push({'Key':'4','Record':{'Account':'a','data':'A3'}});
arr.push({'Key':'5','Record':{'Account':'c','data':'123'}});
const accIdMap= arr.reduce((map,obj) => {
if(map[obj.Record.Account]) { // the property exists and can be an array or the obj
if(!map[obj.Record.Account].length) { // means just the object. Creating an array then pushing the existing obj to it
const m = (map[obj.Record.Account]);
map[obj.Record.Account] = [];
map[obj.Record.Account].push(m);
}
map[obj.Record.Account].push(obj); // if it was an array this will push it to the existing array. If it wasn't the previous if have created and inserted old value and this line pushes to the new array
} else {
map[obj.Record.Account] = obj; // just putting the obj value as it wasn't a duplicate
}
return map;
}, {});
console.log(arr);
console.log(accIdMap);
This works like what you expected. take this result and match with your desired output.
let arr = [];
arr.push({ 'Key': '1', 'Record': { 'Account': 'a', 'data': 'A1' } });
arr.push({ 'Key': '2', 'Record': { 'Account': 'b', 'data': '123' } });
arr.push({ 'Key': '3', 'Record': { 'Account': 'a', 'data': 'A2' } });
arr.push({ 'Key': '4', 'Record': { 'Account': 'a', 'data': 'A3' } });
arr.push({ 'Key': '5', 'Record': { 'Account': 'c', 'data': '123' } });
var obj = {}
arr.map((e) => {
var filteredArr = arr.filter((f) => f.Record.Account == e.Record.Account)
if (filteredArr.length > 1)
obj[e.Record.Account] = filteredArr
else if (filteredArr.length != 0)
obj[e.Record.Account] = filteredArr[0]
})
console.log(JSON.stringify(obj))