How to modify the object and convert to array of objects javascript - javascript

How to change object to array of objects in javascript.
How to modify object and get the new aray of objects in javascript
Expected Result should be as input object weeks x 2 times (4 objects in output array)
for each item.
In Expected Output,
group key represents the weeks columns array,
should create a arraylist of each item desc, and interval qty per week
function createObject(obj){
const results = [];
for (var itm of obj.items) {
group: Object.values(obj.options).map((opt, index)=>opt.start+"-"+opt.end)
}
}
var obj = {
options: {
w1: {start:"Jan",end: "1"},
w2: {start:"Feb", end: "1"}
},
intervals: {
t1: {begin: "1", end: "2", totalqty: 2,totalamt: 200},
t2: {begin: "4", end: "7", totalqty: 3, totalamt: 300},
}
items: [
{
name: "s1",
desc: "sample1",
w1: {t1: {qty:0},t2: {qty:1}},
w2: {t1: {qty:1},t2: {qty:2}}
}
{
name: "s2",
desc: "sample2",
w1: {t1: {qty:0},t2: {qty:0}},
w2: {t1: {qty:0},t2: {qty:1}}
}
]
}
Expected Output:
[
{
group:"Jan 1", // represents w1
columns: [
{
col: 'desc',
value: 'sample1' // item.desc
},
{
col: '1-2', // represents t1
value: 0 , // represents t1.qty
},
{
col: '4-7', // represents t2
value: 1 // represents w1.t2.qty
}
]
},
{
group:"Feb 1", // represents w2
columns: [
{
col: 'desc',
value:'sample1'
},
{
col: '1-2', // represents t1
value:1 , // represents t1.qty
},
{
col: '4-7', // represents t2
value:2 ,// represents t2.qty
}
]
},
{
group:"Jan 1",
columns: [
{
col: 'desc',
value:'sample2'
},
{
col: '1-2',
value:0,
},
{
col: '4-7',
value:0
}
]
},
{
group:"Feb 1",
columns: [
{
col: 'desc',
value:'sample2'
},
{
col: '1-2',
value:0 ,
},
{
col: '4-7',
value:1,
}
]
}
]

Please try the below code. It produces the expected result
function createObject(obj){
return obj.items.map((item) => {
return Object.keys(obj.options).map((optKey) => {
const option = obj.options[optKey];
const items = {
'group' : `${option.start} ${option.end}`,
'columns': [{col: 'desc', value: item.desc}]
};
const intervals = item[optKey];
Object.keys(intervals).forEach((interval) => {
items.columns.push({
col: `${obj.intervals[interval].begin}-${obj.intervals[interval].end}`,
value: intervals[interval].qty
})
})
return items;
})
});
}

Related

How can I access this property in my dictionary in js?

I thought I understood how to loop through a dictionary, but my loop is wrong. I try to access the name of each sub item but my code does not work.
Here is what I did:
list = [
{
title: 'Groceries',
items: [
{
id: 4,
title: 'Food',
cost: 540 ,
},
{
id: 5,
title: 'Hygiene',
cost: 235,
},
{
id: 6,
title: 'Other',
cost: 20,
},
],
}];
function calculateCost(){
let total = 0;
Object.keys(list).forEach((k) => { for (i in k.items) { total += i.data; } });
console.log(total);
return total;
}
Your list is an array includes 1 object and this object has two properties title and items the items here is an array of objects each one of these objects has property cost so to calculate the total cost you need to loop through items array, here is how you do it:
let list = [
{
title: 'Groceries',
items: [
{
id: 4,
title: 'Food',
cost: 540 ,
},
{
id: 5,
title: 'Hygiene',
cost: 235,
},
{
id: 6,
title: 'Other',
cost: 20,
},
],
}];
function calculateCost(){
let total = 0;
list[0].items.forEach(el => {
total += el.cost;
})
console.log(total)
return total;
}
calculateCost();
Your list is an Array, not an Object.
Instead of Object.keys() use Array.prototype.reduce:
const calculateCost = (arr) => arr.reduce((tot, ob) =>
ob.items.reduce((sum, item) => sum + item.cost, tot), 0);
const list = [
{
title: 'Groceries',
items: [
{id: 4, title: 'Food', cost: 10},
{id: 5, title: 'Hygiene', cost: 20},
{id: 6, title: 'Other', cost: 30}
]
}, {
title: 'Other',
items: [
{id: 8, title: 'Scuba gear', cost: 39}
],
}
];
console.log(calculateCost(list)); // 99
Expanding on #Roko's and #mmh4all's answers, the following code adds several verification statements to handle cases where a deeply nested property in your data is not what you expect it to be.
const calculateCost = (orders) => {
let listOfCosts = [];
// For each 'order' object in the 'orders' array,
// add the value of the 'cost' property of each item
// in the order to 'listOfCosts' array.
orders.forEach(order => {
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray
if (!Array.isArray(order.items)) { return; }
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/parseFloat
const orderCostArr = order.items.map(item =>
isNaN(item.cost) ? 0 : parseFloat(item.cost, 10));
if (orderCostArr.length === 0) { return; }
// Concatenate 'orderCostArr' to the 'listOfCosts' array
//listOfCosts = listOfCosts.concat(orderCostArry);
// Alternate approach is to use the spread syntax (...) to
// push the items in the array returned by 'order.items.map()'
// into the 'listOfCosts' array.
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
listOfCosts.push(...orderCostArr);
});
// Use the 'reduce' method on the 'listOfCosts' array
// to get the total cost.
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
const totalCost = listOfCosts.reduce(
(accumulator, currentValue) => accumulator + currentValue, 0);
return totalCost;
};
const list = [
{
title: 'Groceries',
items: [
{ id: 4, title: 'Food', cost: 10 },
{ id: 3, title: 'Baked goods', cost: 20 },
{ id: 5, title: 'Hygiene', cost: 0 },
{ id: 6, title: 'Other' }
]
}, {
title: 'Gear',
items: {},
}, {
title: 'Accessories',
items: [],
}, {
title: 'Bags',
}, {
title: 'Other',
items: [
{ id: 10, title: 'Scuba gear', cost: "5" },
{ id: 8, title: 'Scuba gear', cost: "err" },
{ id: 9, title: 'Scuba gear', cost: 59 }
],
}
];
console.log(calculateCost(list)); // 94

TS/JS, Unable to sum more than one properties, using map set and get

I have been trying to create a summary of an array of objects where it's grouped by the value of one property and 2 or more properties should get summed.
But for some reason the way I am trying is only giving me 2 values the property I am grouping by and first property I am summing.
I am unable to sum the next property.
The array I am starting with
combinedItems
[
{
itemSi: 1,
productId: 'one',
taxableValue: 100,
taxValue: 10,
product: { id: 'one', productName: 'product one', taxId: 'one' },
tax: { id: 'one', taxName: 'tax one' }
},
{
itemSi: 2,
productId: 'two',
taxableValue: 100,
taxValue: 10,
product: { id: 'two', productName: 'product two', taxId: 'one' },
tax: { id: 'one', taxName: 'tax one' }
}
]
I need to be able to group by the taxName and sum the taxableValue and taxValue.
const summaryValues = new Map<any []>();
for(const {tax, taxableValue, taxValue} of combinedItems)
summaryValues.set(
tax.taxName,
(summaryValues.get(tax.taxName) || 0) + taxableValue,
(summaryValues.get(tax.taxName) || 0) + taxValue,
);
const summaries = [...summaryValues]
console.log(summaries);
const taxSummary = summaries.map(x => ({
taxName: x[0],
taxableValue: x[1],
taxValue: x[2]
}));
console.log(taxSummary)
The result I am getting
[ [ 'tax one', 200 ] ]
[ { taxName: 'tax one', taxableValue: 200, taxValue: undefined } ]
This is how the combined items are gotten:
const items: any[] = [
{
itemSi: 1,
productId: "one",
taxableValue: 100,
taxValue: 10
},
{
itemSi: 2,
productId: "two",
taxableValue: 100,
taxValue: 10
}
];
const products: any[] = [
{
id: "one",
productName:"product one",
taxId: "one"
},
{
id: "two",
productName:"product two",
taxId: "one"
}
]
const taxes: any[] = [
{
id: "one",
taxName:"tax one"
},
{
id: "two",
taxName:"tax two"
}
]
let combinedItems: any [] = []
combinedItems = items.map(x => {
let pdtItem = products.find(z => z.id === x.productId);
let taxItem = taxes.find(z => z.id === pdtItem.taxId);
let item = {...x, product: {...pdtItem }, tax: {...taxItem}};
return item;
});
console.log(combinedItems)
Map is a key-value store. What you're trying to do appears to be calling set with three arguments, whereas it only takes two (key and value).
If you need to produce multiple aggregations, you could store the results in an object:
const summaries = new Map();
for (const { tax: { taxName }, taxableValue, taxValue } of combinedItems) {
const currentSummary = summaries.get(taxName) || { taxableValue: 0, taxValue: 0 }
summaries.set(
taxName,
{ taxableValue: currentSummary.taxableValue + taxableValue, taxValue: currentSummary.taxValue + taxValue }
);
}

nested for loops to get another object-array output

I need to multiply all the "values" inside "obj1" with the "percent' inside obj2 based on the id of each object. What would be the best way to do that? I've tried with for loop and reduce but I wasn't successful. Any help will be appreciated.
const obj1 = [ { id: 1, value: 10 }, { id: 2, value: 10 } ]
const obj2 = {
len: {
id: 1,
nj: "321345",
percent: 0.05,
},
wor: {
id: 2,
nj: "321345",
percent: 0.1,
}
}
outputExpected: [ { id: 1, value: 0.5 }, { id: 2, value: 1 } ]
You can do that by going through and matching the ids. there are some optimizations that can be made if they are sorted however.
const obj1 = [ { id: 1, value: 10 }, { id: 2, value: 10 } ]
const obj2 = {
len: {
id: 1,
nj: "321345",
percent: 0.05,
},
wor: {
id: 2,
nj: "321345",
percent: 0.1,
}
}
const x = Object.keys(obj2).map((key,index)=>{
const { id, value } = obj1.find(({id})=>id===obj2[key].id)
return ({id,value:value*obj2[key].percent})
})
console.log(x)
//outputExpected: [ { id: 1, value: 0.5 }, { id: 2, value: 1 } ]
You can first create a lookup map using Map, then loop over the obj1 using map to get the desired result
const obj1 = [
{ id: 1, value: 10 },
{ id: 2, value: 10 },
];
const obj2 = {
len: {
id: 1,
nj: "321345",
percent: 0.05,
},
wor: {
id: 2,
nj: "321345",
percent: 0.1,
},
};
const map = new Map();
Object.values(obj2).forEach((v) => map.set(v.id, v));
const result = obj1.map((o) => ({ ...o, value: o.value * map.get(o.id).percent }));
console.log(result);
This should work for you but doesnt handle exeptions if the id doesnt exist in both objects.
// First get the values in an array for easier manipulation
const aux = Object.values(obj2)
const output = obj1.map(ob => {
// Find the id in the other array.
const obj2Ob = aux.find(o => o.id === ob.id) // The id must exist in this aproach
return {
id: ob.id,
value: ob.value * obj2Ob.percent
}
})
console.log(output) // [ { id: 1, value: 0.5 }, { id: 2, value: 1 } ]

Flatten Nested Objects and Output Array

I have a deeply nested object that has the following schema:
const data = {
Car1: {
key: "Car",
value: "1",
child: {
Driver1: {
key: "Driver",
value: "1",
child: {
Trip1: {
key: "Trip",
value: 1,
metrics: { distance: 1, time: 2 }
}
}
},
Driver2: {
key: "Driver",
value: "2",
child: {
Trip1: {
key: "Trip",
value: 1,
metrics: { distance: 3, time: 4 }
},
Trip2: {
key: "Trip",
value: 2,
metrics: { distance: 5, time: 6 }
}
}
}
}
}
}
That I need to flatten into a singular array of objects, with each object in the array having all the properties of its direct child(ren).
Each nested object child is a Record of objects that have properties key and value.
The last object in the nested structure always has a property called metrics that should be flattened into the object as well.
So the output would look something like:
[
{ Car: 1, Driver: 1, Trip: 1, distance: 1, time: 2 },
{ Car: 1, Driver: 2, Trip: 1, distance: 3, time: 4 },
{ Car: 1, Driver: 2, Trip: 2, distance: 5, time: 6 }
]
I have tried the following code but it only captures one level of depth in the child tree:
private flattenOutput(child: Record<string, OutputChild> = this.output): any[] {
console.log('flattening', Object.keys(child));
return Object.values(child).map((child) => {
return Object.assign(
{},
{ [child.key]: child.value },
...this.flattenOutput(child.child),
child.metrics || {},
);
}, {});
}
By having correct nested objects, you could take a recursive approach and collect key/value and return a flat array with wanted objects.
const
collect = (object, temp = {}) => Object
.values(object)
.flatMap(({ key, value, child, metrics }) => child
? collect(child, { ...temp, [key]: value })
: { ...temp, [key]: value , ...metrics }
),
data = { Car1: { key: "Car", value: "1", child: { Driver1: { key: "Driver", value: "1", child: { Trip1: { key: "Trip", value: 1, metrics: { distance: 1, time: 2 } } } }, Driver2: { key: "Driver", value: "2", child: { Trip1: { key: "Trip", value: 1, metrics: { distance: 3, time: 4 } }, Trip2: { key: "Trip", value: 2, metrics: { distance: 5, time: 6 } } } } } } },
result = collect(data);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I will do that this way :
data =
{ Car1: { key: "Car", value: "1", child:
{ Driver1: { key: "Driver", value: "1", child:
{ Trip1: { key: "Trip", value: 1, metrics: { distance: 1, time: 2} }
} }
, Driver2:
{ key: "Driver", value: "2", child:
{ Trip1: { key: "Trip", value: 1, metrics: { distance: 3, time: 4} }
, Trip2: { key: "Trip", value: 2, metrics: { distance: 5, time: 6} }
} } } } }
let result = []
for (let Car in data )
for (let Driver in data[Car].child)
for (let Trip in data[Car].child[Driver].child)
result.push(
{ Car : data[Car].value
, Driver : data[Car].child[Driver].value
, Trip : data[Car].child[Driver].child[Trip].value
, distance : data[Car].child[Driver].child[Trip].metrics.distance
, time : data[Car].child[Driver].child[Trip].metrics.time
})
console.log( result )
.as-console-wrapper { max-height: 100% !important; top: 0; }

JavaScript - Is there a simple way to get the values for every occurrence of a specific key in nested JSON

I have a JSON structure similar to this:
[
{
cells: [
{ id: "1", cellType: 3, widget: { id: 1, description: "myDesc"} },
{ id: "2", cellType: 4, widget: { id: 2, description: "myDesc2"} }
]
},
{
cells: [
{ id: "3", cellType: 5, widget: { id: 3, description: "myDesc3"} }
]
},
...
]
How do I get the value of every widget into a separate array using EcmaScript (or anything that's available in Angular 2+), and without using a library (including JQuery)? I need a final array like this:
[
{
id: 1,
description: "myDesc"
},
{
id: 2,
description: "myDesc2"
},
...
]
Update
(and thanks to #Felix Kling for the 1st part) - I found I can get all of the widgets with this:
JSON.parse(json)[0].forEach( c => c.cells.forEach( c2 => console.log(c2.widget)));
You can use .map() with .reduce()
let input = [
{
cells: [
{ id: "1", cellType: 3, widget: { id: 1, description: "myDesc"} },
{ id: "1", cellType: 4, widget: { id: 2, description: "myDesc2"} }
]
},
{
cells: [
{ id: "3", cellType: 5, widget: { id: 3, description: "myDesc3"} }
]
},
];
let result = input.reduce((result, current) => {
return result.concat(current.cells.map(x => x.widget));
}, [])
console.log(result);
You can use .map() and .concat() to get the desired result:
let data = [{
cells: [
{ id: "1", cellType: 3, widget: { id: 1, description: "myDesc"} },
{ id: "1", cellType: 4, widget: { id: 2, description: "myDesc2"} }
]}, {
cells: [
{ id: "3", cellType: 5, widget: { id: 3, description: "myDesc3"} }
]
}];
let result = [].concat(...data.map(({cells}) => cells.map(({widget}) => widget)));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Categories

Resources