Nested key value pair grouping into an array - javascript

I have an Object with nested key value pair as:
Products:{
Clip:{
today_entry: 0,
today_sold: 0
},
Necklace:
{
today_entry: 0,
today_sold: 2
}
}
I want to loop through the Objects Clip ad Necklace and group the values as per their inner keys i.e. today_entry, today_sold into the format:
{
today_entry : [0,0],
today_sold : [0,2]
}
I tried doing it using Object.entries but since it is nested I'm not able to get the inner keys. Could anyone please help me? Thank you.

You can use reudce:
const products = {
Clip:{
today_entry: 0,
today_sold: 0,
},
Necklace:
{
today_entry: 0,
today_sold: 2,
},
};
const result = Object.keys(products).reduce((ac, key) => ({
today_entry: [ ...ac.today_entry, products[key].today_entry],
today_sold: [ ...ac.today_sold, products[key].today_sold],
}), { today_entry: [], today_sold: []});
console.log(result);
In case the order of the values in the arrays are important you should also sort the keys the way you want.

It is possible to use reduce() method to create an object with Object.values() to get values from object:
const result = Object.values(products).reduce((a, c) => {
for (const key in c) {
a[key] = a[key] || [];
a[key].push(c[key]);
}
return a;
},{});
An example:
let products = {
Clip:{
today_entry: 0,
today_sold: 0
},
Necklace:
{
today_entry: 0,
today_sold: 2
}
}
const result = Object.values(products).reduce((a, c) => {
for (const key in c) {
a[key] = a[key] || [];
a[key].push(c[key]);
}
return a;
},{});
console.log(result)

const products = {
Clip:{
today_entry: 0,
today_sold: 0
},
Necklace:
{
today_entry: 0,
today_sold: 2
}
}
const result = {};
for(item in products) {
for (action in products[item]) {
result[action]= result[action]||[];
result[action].push(products[item][action])
}
}
console.log(result)
//{ today_entry: [ 0, 0 ], today_sold: [ 0, 2 ] }

Related

How to merge a nested array of objects in javascript with a specific shape

I am trying to merge an array of objects by summing up the totals of each key-value pair under the totals object. For example, the below array would yield one object with a totals object of 3 apples and 5 oranges. This should be dynamic. If pears were to be a key in another object, the resulting object would include three keys under the totals object: apples, oranges, and pears.
Sample Input:
[
{
summary: {
totals: {
apples: 2,
oranges: 3
}
}
},
{
summary: {
totals: {
apples: 1,
oranges: 2
}
}
}
]
Expected Output:
{
summary:{
totals:{
apples:3,
oranges:5
}
}
}
What I've tried:
function mergeObjects(arr) {
let shape = {
summary:{
totals:{}
}
}
return arr.reduce((prev, cur) => {
if(cur.summary.totals.apples){
shape.summary.totals.apples.push(cur.summary.totals.apples)
}
}, shape);
}
Using Array#reduce, iterate over the array while updating an object
In every iteration, using Object#entries and
, iterate over the current totals pairs and update the accumulator.
const arr = [
{ summary: { totals: { apples: 2, oranges: 3 } } },
{ summary: { totals: { apples: 1, oranges: 2 } } },
];
const res = arr.reduce((map, current) => {
const { totals: currentTotals = {} } = current.summary ?? {};
const { totals } = map.summary;
Object.entries(currentTotals).forEach(([ key, value ]) => {
totals[key] = (totals[key] ?? 0) + value;
});
return map;
}, { summary: { totals: {} } });
console.log(res);
You can try something like. Just loop through the array and sum up apples and oranges.
const arr = [
{
summary: {
totals: {
apples: 2,
oranges: 3,
},
},
},
{
summary: {
totals: {
apples: 1,
oranges: 2,
},
},
},
];
function mergeObjects(arr) {
let shape = {
summary:{
totals:{
apples:0,
oranges:0
}
}
}
arr.forEach(x => {
if(x.summary.totals.apples){
shape.summary.totals.apples += x.summary.totals.apples;
shape.summary.totals.oranges += x.summary.totals.oranges;
}
});
return shape;
}
let result = mergeObjects(arr);
console.log(result);
The second option of the reduce function initializes the value.
And the initialized value can be used in prev!
[1] store the value in prev.
[2] prev can accumulate values. You have to return to use the accumulated value. If not returned, the value will be undefined.
[3] apples is not an array type, so you cannot use the push method. it is a number type, you must use a numeric operator.
function mergeObjects(arr) {
const shape = {
summary: {
totals: {},
},
};
return arr.reduce((prev, cur) => {
const { apples, oranges } = cur.summary.totals;
// [1]
prev.summary.totals.apples
// [3]
? (prev.summary.totals.apples += apples)
: (prev.summary.totals.apples = apples);
prev.summary.totals.oranges
? (prev.summary.totals.oranges += oranges)
: (prev.summary.totals.oranges = oranges);
// [2]
return prev;
}, shape);
}
tips!
Use Destructuring Assignment
const { apples, oranges } = cur.summary.totals;
Use Ternary Operator
prev.summary.totals.apples
? (prev.summary.totals.apples += apples)
: (prev.summary.totals.apples = apples);
Make code look nice!
You can combine Object.entries() with Array#reduce() and Array.forEach()
Code:
const data = [{summary: {totals: {apples: 2,oranges: 3}}},{summary: {totals: {apples: 1,oranges: 2}}}]
const result = data.reduce((a, c) => {
Object
.entries(c.summary.totals)
.forEach(([k, v]) => a.summary.totals[k] += v)
return a
},
{ summary: { totals: { apples: 0, oranges: 0 } } })
console.log(result)

JS Turn an array into Object with property key/value

i was coding and i found this problem, the goal is turn the items array into a object with property key/value, counting the items that appear more than once like that:
{
cookie:{
MILK: 1,
CHOCOLATE: 2,
DELUXE: 1
},
bread:{
BIG: 2
},
beer:{
NEW: 1,
OLD: 1
}
}
I tried this code below
const items = [
"cookie-MILK",
"cookie-CHOCOLATE",
"cookie-CHOCOLATE",
"cookie-DELUXE",
"bread-BIG",
"bread-BIG",
"beer-NEW",
"beer-OLD"
]
let newArray = [];
items.forEach((e) => {
let splitArray = e.split("-");
newArray.push([splitArray[0], splitArray[1]]);
});
let result = newArray.reduce((acc, val) => {
if (!acc[val[0]] && !acc[val[1]] ) acc[val[0]] = {
[val[1]]: 1,
};
else acc[val[0]][val[1]]++;
return acc;
}, {});
But this code returns it and i don't know how to solve this question
{
cookie:{
MILK: 1,
CHOCOLATE: NaN,
DELUXE: NaN
},
bread:{
BIG: 2
},
beer:{
NEW: 1,
OLD: NaN
}
}
You could take a logical nullish assignment ??= for assigning an object or zero and increment the value.
const
items = ["cookie-MILK", "cookie-CHOCOLATE", "cookie-CHOCOLATE", "cookie-DELUXE", "bread-BIG", "bread-BIG", "beer-NEW", "beer-OLD"],
result = items.reduce((acc, val) => {
const [left, right] = val.split("-");
(acc[left] ??= {})[right] ??= 0;
acc[left][right]++;
return acc;
}, {});
console.log(result);
I think is beter solution:
const items = [
"cookie-MILK",
"cookie-CHOCOLATE",
"cookie-CHOCOLATE",
"cookie-DELUXE",
"bread-BIG",
"bread-BIG",
"beer-NEW",
"beer-OLD"
];
let res = {};
items.forEach(item => {
let itemParsed = item.split("-");
if(typeof res[itemParsed[0]] == "undefined")
res[itemParsed[0]] = {}
if(typeof res[itemParsed[0]][itemParsed[1]] == "undefined")
res[itemParsed[0]][itemParsed[1]] = 0;
res[itemParsed[0]][itemParsed[1]]++;
})
console.log(res)

javascript convert for loop filter on index to functional programming

I have got the following code that returns an object based on a filter
i want to convert this to functional programming using map, filter.
var records_object = {
"record": [
"analog",
"laser",
"monochrome",
"digital"
],
"vcd": [
12,
3,
6,
0
],
"dvd": [
1,
0,
0,
16
]
}
var arr_idx = [];
for (i = 0; i < records_object.record.length; i++) {
if (records_object.record[i].match(/digital/i) != null||
records_object.record[i].match(/analog/i) != null) {
arr_idx.push(i);
}
}
for (el in records_object) {
records_object[el] = records_object[el].filter(function (x, i) {
return arr_idx.indexOf(i) != -1;
});
}
console.log(records_object);
so far i was able to do this , now i am stuck
const getIndex = (data) => {
return data.record
.map((e, i) =>
e.includes("analog") || e.includes("digital") ? i : undefined
)
.filter((x) => x !== undefined);
};
You can do this,
var records_object = {
"record": [
"analog",
"laser",
"monochrome",
"digital"
],
"vcd": [
12,
3,
6,
0
],
"dvd": [
1,
0,
0,
16
]
}
let arrayIndexes = records_object.record.map((item, index) => {
if(item.match(/digital/i) != null || item.match(/analog/i) !== null) {
return index;
}
}).filter(item => item !== undefined);
let newObject = Object.keys(records_object).reduce((prev, key) => {
prev[key] = records_object[key].filter((item, index) => arrayIndexes.includes(index));
return prev;
}, {});
console.log(newObject);
The problem was with filter.
when you are running map it returns array [0, undefined, undefined, 3] and that array is being filtered and as you are using filter(x => x), this will iterate through the returned array and remove all the falsy values and return the resulting array.
In [0, undefined, undefined, 3]'s case, only 3 is the truthy value and that's why you are getting only [3] as 0 too is falsy.
You can modify your code slightly to get this resolved.
var records_object = {
record: ["analog", "laser", "monochrome", "digital"],
vcd: [12, 3, 6, 0],
dvd: [1, 0, 0, 16],
};
const getIndex = (data) => {
return data.record
.map((e, i) =>
e.includes("analog") || e.includes("digital") ? i : undefined
)
.filter((x) => x !== undefined);
};
console.log(getIndex(records_object));
Here is the solution using reduce and filter function. I've saved the result in new object.
var records_object = {
"record": [
"analog",
"laser",
"monochrome",
"digital"
],
"vcd": [
12,
3,
6,
0
],
"dvd": [
1,
0,
0,
16
]
};
const matchByString = ['analog', 'digital'];
const isMatch = (el, stringElements) => stringElements.some((strEl) => el.match(new RegExp(strEl, 'i')) != null);
const filterByIndex = records_object.record.reduce((acc, el, index) => isMatch(el, matchByString) ? [...acc, index] : acc, [])
const result = {};
Object.keys(records_object).forEach(i => result[i] = records_object[i].filter((el, i) => filterByIndex.includes(i)));
console.log(result)

How to concatenate object values with same id

I have an array:
let ar = [
{
uid:1,
flat_no: 1
},
{
uid:2,
flat_no: 2
},
{
uid:1,
flat_no:3
}
];
If uid are same then I want to remove duplicate uid and concatenate its flat_no. The output array should be like this:
[
{
uid:1,
flat_no: [1,3]
},
{
uid:2,
flat_no: 2
}
];
You can use a combination of Array.reduce and Array.find.
If you find an existing item in your accumulator array, just update it's flat_no property, otherwise push it to the accumulator array.
let arr = [
{
uid: 1,
flat_no: 1
},
{
uid: 2,
flat_no: 2
},
{
uid: 1,
flat_no: 3
}
]
arr = arr.reduce((arr, item) => {
const existing = arr.find(innerItem => innerItem.uid === item.uid)
if (existing) {
existing.flat_no = Array.isArray(existing.flat_no)
? existing.flat_no
: [existing.flat_no]
existing.flat_no.push(item.flat_no)
} else {
arr.push(item)
}
return arr
}, [])
console.log(arr)
You can iterate over your array and fill an object (used as a hashmap here).
Once done, you extract the values to get your result.
let hashResult = {}
ar.forEach(element => {
if (hashResult[element.uid] == undefined) {
hashResult[element.uid] = { uid: element.uid, flat_no: [] }
}
hashResult[element.uid].flat_no.push(element.flat_no)
})
let result = Object.values(hashResult)
console.log(new Date(), result)
You can do this in a concise way with a single Array.reduce and Object.values to match your desired output:
let data = [ { uid:1, flat_no: 1 }, { uid:2, flat_no: 2 }, { uid:1, flat_no:3 } ];
const result = data.reduce((r, {uid, flat_no}) => {
r[uid] ? r[uid].flat_no = [r[uid].flat_no, flat_no] : r[uid] = {uid, flat_no}
return r
}, {})
console.log(Object.values(result))
1)Reduce the initial array to an object which has uid as the key and the flat_no as the value.
2)Then run a map on the keys to convert it into an array of objects with uid and flat_no.
1) First Step Code
let ar = [{uid:1, flat_no: 1},{uid:2, flat_no: 2},{uid:1, flat_no:3}];
let outputObj = ar.reduce((outputObj,currObj,currIndex) => {
let {uid,flat_no} = currObj
if (outputObj[uid]) {
outputObj[uid].push(flat_no)
}
else {
outputObj[uid] = [flat_no]
}
return outputObj
},{})
2)
let finalOutput = Object.keys(outputObj).map(key =>
({uid:key,flat_no:outputObj[key]}))
console.log(finalOutput)

Es6 way to convert object key value to one single object

I want to convert all data into one object,
let d = {
"Coupon_Code": "code",
"Coupon_Name": "namie",
"Coupon_Desc": 1000,
"selectedCity": [
{
"Coupon_City_Name": "xyz"
}
],
"selectedCategory": [
{
"Coupon_Category_Name": "Shopping"
}
],
"selectedCompany": [
{
"Coupon_Company_Name": "Shopper Stop"
}
],
"selectedState": [
{
"Coupon_State_Name": "abc"
}
],
"Coupon_Date": "2222-02-22",
}
i tried some methods of Object like keys , entries but dont no what to use.
Final output should be
let d = {
Coupon_Code: "code",
Coupon_Name: "namie",
Coupon_Desc: 1000,
Coupon_City_Name: "xyz",
Coupon_Category_Name: "Shopping",
Coupon_Company_Name: "Shopper Stop",
Coupon_State_Name: "abc",
Coupon_Date: "2222-02-22",
};
what's the best and optimum way to have above result using Venila Js and Es6
Reduce the entries of the original object. If the entry's value is an array merge the 1st element, if not merge the original key and value. You can merge the properties into the object using object spread:
const data = {"Coupon_Code":"code","Coupon_Name":"namie","Coupon_Desc":1000,"selectedCity":[{"Coupon_City_Name":"xyz"}],"selectedCategory":[{"Coupon_Category_Name":"Shopping"}],"selectedCompany":[{"Coupon_Company_Name":"Shopper Stop"}],"selectedState":[{"Coupon_State_Name":"abc"}],"Coupon_Date":"2222-02-22"};
const result = Object.entries(data)
.reduce((r, [k, v]) => ({
...r,
...Array.isArray(v) ? v[0] : { [k]: v }
}), {});
console.log(result);
You can use Array.reduce and Object.entries
let d = {"Coupon_Code":"code","Coupon_Name":"namie","Coupon_Desc":1000,"selectedCity":[{"Coupon_City_Name":"xyz"}],"selectedCategory":[{"Coupon_Category_Name":"Shopping"}],"selectedCompany":[{"Coupon_Company_Name":"Shopper Stop"}],"selectedState":[{"Coupon_State_Name":"abc"}],"Coupon_Date":"2222-02-22"};
d = Object.entries(d).reduce((a,[k,v]) => {
// If the value is an array, iterate over it to merge into the resultant object
if(Array.isArray(v)) Object.assign(a, ...v)
else Object.assign(a, {[k]:v}) // if it is not an array, merge into resultant object
return a;
}, {});
console.log(d);
You could take a recursive approach.
const
fn = o => Object.assign(...Object.entries(o).map(([k, v]) => Array.isArray(v) ? Object.assign(...v.map(fn)) : { [k]: v })),
d = { Coupon_Code: "code", Coupon_Name: "namie", Coupon_Desc: 1000, selectedCity: [{ Coupon_City_Name: "xyz" }], selectedCategory: [{ Coupon_Category_Name: "Shopping" }], selectedCompany: [{ Coupon_Company_Name: "Shopper Stop" }], selectedState: [{ Coupon_State_Name: "abc" }], Coupon_Date: "2222-02-22" },
result = fn(d);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
A possible iterative solution is:
function flatten(obj) {
let r = {}
for (let [key, value] of Object.entries(obj)) {
if (Array.isArray(value)) {
Object.assign(r, value[0]);
} else {
Object.assign(r, {[key]: value});
}
}
return r;
}
Something like this:
const d = { Coupon_Code: "code", Coupon_Name: "namie", Coupon_Desc: 1000, selectedCity: [{ Coupon_City_Name: "xyz" }], selectedCategory: [{ Coupon_Category_Name: "Shopping" }], selectedCompany: [{ Coupon_Company_Name: "Shopper Stop" }], selectedState: [{ Coupon_State_Name: "abc" }], Coupon_Date: "2222-02-22" };
function toSingleObj(obj) {
var result = {};
Object.entries(obj).forEach(([key,value]) => {
if (Array.isArray(value)) {
Object.entries(value[0]).forEach(([k,v]) => {
result[k] = v;
});
} else {
result[key] = value;
}
});
return result;
}
console.log("Result: ", toSingleObj(d));

Categories

Resources