working with nested object - javascript

I think this is silly question and simple but I can't find any result in google and other resource
I have array of object like this
const myArr = [
[{
id: 1,
price: 200,
}, {
id: 2,
price: 900,
}, {
id: 3,
price: 100,
}],
[{
id: 5,
price: 100,
}]
];
In other word I have an array and my array contain some array and each of inner array contain some object inside them
arr [ [ {},{},{} ] , [ {} ] ]
now I want get two thing
count of all products ?
sum of all products ?
*(each object = one product)

Flatten to a single array by spreading into Array.concat().
Use Array.reduce() to get the sum.
The count is flattened array's length.
const myArr = [[{"id":1,"price":200},{"id":2,"price":900},{"id":3,"price":100}],[{"id":5,"price":100}]];
const flattened = [].concat(...myArr);
const count = flattened.length;
const sum = flattened.reduce((s, o) => s + o.price, 0);
console.log('count', count);
console.log('sum', sum);

You can use spread to flat the array:
var myArr = [
[
{
id:1,
price:200,
},
{
id:2,
price:900,
},
{
id:3,
price:100,
}
],
[
{
id:5,
price:100,
}
]
];
var arr = [].concat(...myArr);
console.log('Length: ', arr.length);
var sum = arr.reduce((m, o) => m + o.price, 0);
console.log('Sum: ', sum);

You can use concat to wrap all objects within one single array.
Apply length property in order to find out the number of objects in the array and then reduce method to get the sum.
const myArr = [ [ { id:1, price:200, }, { id:2, price:900, }, { id:3, price:100, } ], [ { id:5, price:100, } ] ];
arr = myArr.reduce((acc, arr) => acc.concat(arr), []);
sum = arr.reduce((acc, item) => acc + item.price, 0);
console.log('count ' + arr.length);
console.log('sum ' + sum)

ES6
You can also use reduce method of array to get the required result
reduce can be used to iterate through the array, adding the current element value to the sum of the previous element values.
DEMO
const myArr = [[{id: 1,price: 200,}, {id: 2,price: 900,}, {id: 3,price: 100,}],[{id: 5,price: 100,}]];
let result = myArr.reduce((r,v)=>{
r.count += v.length;
r.sum += v.reduce((total,{price}) => total+price,0);
return r;
},{count:0,sum:0})
console.log(result);
.as-console-wrapper {max-height: 100% !important;top: 0;}

Related

Create an array of objects based on an object if one or more properties have multiple values differentiated by a comma

i'm trying to duplicate objects based on two properties that have multiple values differentiated by a comma.
For example:
I have an object
const obj = {
id: 1
date: "2021"
tst1: "111, 222"
tst2: "AAA, BBB"
}
And I would like the result to be an array of 2 objects in this case (because there are 2 values in tst1 OR tst2, these 2 properties will always have the same nr of values differentiated by a comma)
[{
id: 1,
date: "2021",
tst1: "111",
tst2: "AAA",
},
{
id: 1,
date: "2021",
tst1: "222",
tst2: "BBB",
}]
What I tried is this:
I created a temporary object
const tempObject = {
id: obj.id,
date: obj.date,
}
And then I would split and map the property that has multiple values, like this:
cont newObj = obj.tst1.split(",").map(function(value) {
let finalObj = {}
return finalObj = {
id: tempObject.id,
date: tempObject.date,
tst1: value,
})
And now, the newObj is an array of objects and each object contains a value of tst1.
The problem is I still have to do the same for the tst2...
And I was wondering if there is a simpler method to do this...
Thank you!
Here is an example that accepts an array of duplicate keys to differentiate. It first maps them to arrays of entries by splitting on ',' and then trimming the entries, then zips them by index to create sub-arrays of each specified property, finally it returns a result of the original object spread against an Object.fromEntries of the zipped properties.
const mapDuplicateProps = (obj, props) => {
const splitProps = props.map((p) =>
obj[p].split(',').map((s) => [p, s.trim()])
);
// [ [[ 'tst1', '111' ], [ 'tst1', '222' ]], [[ 'tst2', 'AAA' ], [ 'tst2', 'BBB' ]] ]
const dupeEntries = splitProps[0].map((_, i) => splitProps.map((p) => p[i]));
// [ [[ 'tst1', '111' ], [ 'tst2', 'AAA' ]], [[ 'tst1', '222' ], [ 'tst2', 'BBB' ]] ]
return dupeEntries.map((d) => ({ ...obj, ...Object.fromEntries(d) }));
};
const obj = {
id: 1,
date: '2021',
tst1: '111, 222',
tst2: 'AAA, BBB',
};
console.log(mapDuplicateProps(obj, ['tst1', 'tst2']));
Not sure if that's what you're searching for, but I tried making a more general use of what you try to do:
const duplicateProperties = obj => {
const properties = Object.entries(obj);
let acc = [{}];
properties.forEach(([key, value]) => {
if (typeof value === 'string' && value.includes(',')) {
const values = value.split(',');
values.forEach((v, i) => {
if (!acc[i]) {
acc[i] = {};
}
acc[i][key] = v.trim();
});
} else {
acc.forEach(o => o[key] = value);
}
});
return acc;
};
const obj = {
id: 1,
date: '2021',
tst1: '111, 222',
tst2: 'AAA, BBB',
};
console.log(duplicateProperties(obj));
You could start by determining the length of the result using Math.max(), String.split() etc.
Then you'd create an Array using Array.from(), returning the correct object for each value of the output index.
const obj = {
id: 1,
date: "2021",
tst1: "111, 222",
tst2: "AAA, BBB",
}
// Determine the length of our output array...
const length = Math.max(...Object.values(obj).map(s => (s + '').split(',').length))
// Map the object using the relevant index...
const result = Array.from({ length }, (_, idx) => {
return Object.fromEntries(Object.entries(obj).map(([key, value]) => {
const a = (value + '').split(/,\s*/);
return [key, a.length > 1 ? a[idx] : value ]
}))
})
console.log(result)
.as-console-wrapper { max-height: 100% !important; }

array of arrays conversion in Javascript

I need to create an array of array.
It is worth noting that the database is very large and that if any attribute does not have a corresponding value, it sends an empty string. I've tried with map and reduce but I wasn't successful:
Any help will be appreciated.
Below I show an example of the expected output:
outputExpected = [
["id", 1, 2],
["name", "name1", "name2"],
["price", 6.95, 998.95],
["promoPrice", 5.91, 333.91],
["category", "test1 | test2", "test3 | test4"],
]
Any way to solve this problem performatically?
this is my code:
let arrayObj = [{
"id": 1,
"name": "name1",
"price": 6.95,
"promoPrice": 5.91,
"category": ["test1, test2"]
},
{
"id": 2,
"name": "name2",
"price": 998.95,
"promoPrice": 333.91,
"category": ["test3, test4"]
}
]
const headers = ["id", "name", "price", "promoPrice", "category"]
const result1 = headers.concat(arrayObj.map((obj) => {
return headers.reduce((arr, key) => {
arr.push(obj[key]) return arr;
}, [])
}))
console.log(result1)
Reduce the array to a Map. On each iteration convert the object to an array of [key, value] pairs using Object.entries(). Use Array.forEach() to iterate the entries and add them to the map. Convert the Map's values iterator to an array using Array.from():
const arr = [{"id":1,"name":"name1","price":6.95,"promoPrice":5.91,"category":["test1", "test2"]},{"id":2,"name":"name2","price":998.95,"promoPrice":333.91,"category":["test3", "test4"]}]
const result = Array.from(arr.reduce((acc, o) => {
Object.entries(o)
.forEach(([k, v]) => {
if(!acc.has(k)) acc.set(k, [k])
acc.get(k).push(Array.isArray(v) ? v.join(' | ') : v)
})
return acc
}, new Map()).values())
console.log(result)
You could simply map the value and check if an item is an array, then take the joined values or the value itself.
const
data = [{ id: 1, name: "name1", price: 6.95, promoPrice: 5.91, category: ["test1, test2"] }, { id: 2, name: "name2", price: 998.95, promoPrice: 333.91, category: ["test3, test4"] }],
headers = ["id", "name", "price", "promoPrice", "category"],
result = data
.reduce(
(r, o) => headers.map((k, i) => [
...r[i],
Array.isArray(o[k]) ? o[k].join(' | ') : o[k]
]),
headers.map(k => [k]),
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
construct one init array with all possible keys with the wanted order, then uses Array.reduce and Array.forEach to Array.push value for per key based on its index.
const arrayObj = [
{
"id":1,
"name":"name1",
"price":6.95,
"promoPrice":5.91,
"category":["test1", "test2"]
},
{
"id":2,
"name":"name2",
"price":998.95,
"promoPrice":333.91,
"category":["test3", "test4"]
}
]
function ConvertToArray2D (items) {
let init = [['id'], ['name'], ['price'], ['promoPrice'], ['category']]
if (!items) return init
return arrayObj.reduce((pre, cur) => {
init.forEach((key, index) => {
pre[index].push(Array.isArray(cur[key[0]]) ? cur[key[0]].join('|') : cur[key[0]])
})
return pre
}, init.slice())
}
console.log(ConvertToArray2D(arrayObj))
This can be handled with a standard 'zip' after mapping your objects to arrays of values in line with the headers array. (This also allows for the result to be pivoted back).
//** #see https://stackoverflow.com/a/10284006/13762301
const zip = (...rs) => [...rs[0]].map((_, c) => rs.map((r) => r[c]));
const headers = ['id', 'name', 'price', 'promoPrice', 'category'];
const arrayObj = [{ id: 1, name: 'name1', price: 6.95, promoPrice: 5.91, category: ['test1', 'test2'] },{ id: 2, name: 'name2', price: 998.95, promoPrice: 333.91, category: ['test3', 'test4'] },];
const result = zip(
headers,
...arrayObj.map((o) => headers.map(h => Array.isArray(o[h]) ? o[h].join(' | ') : o[h]))
);
console.log(result);
// which also allows it to be reversed
console.log(zip(...result));
.as-console-wrapper { max-height: 100% !important; top: 0; }
see: Javascript equivalent of Python's zip function for further zip discussion.

How to convert nested array of objects into one array of objects using javaScript?

I have array which contains affiliate arrays, I don't want to access children of the array by index, my aim is to merge this data and and get the following result: [{id:'11223', price:92},{id:'92221', price:90}], What is the best way to achieve this? Thanks.
Sum of the final reulst:
let finalResult = [{id:'11223', price:92},{id:'92221', price:90}]
let sum = finalResult.reduce((acc, curr)=> {
return acc+ curr.price
}, 0)
console.log(sum)
`
Nested array:
let nestedArray = [
[
{
id:'11223',
price:92
}
],
[
{
id:'92221',
price:90
}
]
]
You can simply flat the nestedArray as:
nestedArray.flat()
let nestedArray = [
[
{
id: "11223",
price: 92,
},
],
[
{
id: "92221",
price: 90,
},
],
];
const arr = nestedArray.flat();
console.log(arr);

How to dedupe an array of objects by a key value pair?

// This is a large array of objects, e.g.:
let totalArray = [
{"id":"rec01dTDP9T4ZtHL4","fields":
{"user_id":170180717,"user_name":"abcdefg","event_id":516575,
}]
let uniqueArray = [];
let dupeArray = [];
let itemIndex = 0
totalArray.forEach(x => {
if(!uniqueArray.some(y => JSON.stringify(y) === JSON.stringify(x))){
uniqueArray.push(x)
} else(dupeArray.push(x))
})
node.warn(totalArray);
node.warn(uniqueArray);
node.warn(dupeArray);
return msg;
I need my code to identify duplicates in the array by a key value of user_id within the objects in the array. Right now, my code works to identify identical objects in the array, but I need it to identify dupes based on a key value inside the objects instead. How do I do this? I am struggling to figure out how to path the for each loop to identify the dupe based on the key value instead of the entire object.
Right now, my code works to identify identical objects in the array, but I need it to identify dupes based on a key value inside the objects instead. How do I do this?
Don’t compare the JSON representation of the whole objects then, but only their user_id property specifically.
totalArray.forEach(x => {
if(!uniqueArray.some(y => y.fields.user_id === x.fields.user_id)){
uniqueArray.push(x)
} else(dupeArray.push(x))
})
You could take a Set and push to either uniques or duplicates.
var array = [
{ id: 1, data: 0 },
{ id: 2, data: 1 },
{ id: 2, data: 2 },
{ id: 3, data: 3 },
{ id: 3, data: 4 },
{ id: 3, data: 5 },
],
uniques = [],
duplicates = [];
array.forEach(
(s => o => s.has(o.id) ? duplicates.push(o) : (s.add(o.id), uniques.push(o)))
(new Set)
);
console.log(uniques);
console.log(duplicates);
.as-console-wrapper { max-height: 100% !important; top: 0; }
One way is to keep a list of ids you found so far and act accordingly:
totalArray = [
{ id: 1, val: 10 },
{ id: 2, val: 20 },
{ id: 3, val: 30 },
{ id: 2, val: 15 },
{ id: 1, val: 50 }
]
const uniqueArray = []
const dupeArray = []
const ids = {}
totalArray.forEach( x => {
if (ids[x.id]) {
dupeArray.push(x)
} else {
uniqueArray.push(x)
ids[x.id] = true
}
})
for (const obj of uniqueArray) console.log("unique:",JSON.stringify(obj))
for (const obj of dupeArray) console.log("dupes: ",JSON.stringify(obj))

how to count duplicate values object to be a value of object

how to count the value of object in new object values
lets say that i have json like this :
let data = [{
no: 3,
name: 'drink'
},
{
no: 90,
name: 'eat'
},
{
no: 20,
name: 'swim'
}
];
if i have the user pick no in arrays : [3,3,3,3,3,3,3,3,3,3,3,90,20,20,20,20]
so the output should be an array
[
{
num: 3,
total: 11
},
{
num: 90,
total: 1
},
{
num:20,
total: 4
}
];
I would like to know how to do this with a for/of loop
Here is the code I've attempted:
let obj = [];
for (i of arr){
for (j of data){
let innerObj={};
innerObj.num = i
obj.push(innerObj)
}
}
const data = [{"no":3,"name":"drink"},{"no":90,"name":"eat"},{"no":20,"name":"swim"}];
const arr = [3,3,3,3,3,3,3,3,3,3,3,20,20,20,20,80,80];
const lookup = {};
// Loop over the duplicate array and create an
// object that contains the totals
for (let el of arr) {
// If the key doesn't exist set it to zero,
// otherwise add 1 to it
lookup[el] = (lookup[el] || 0) + 1;
}
const out = [];
// Then loop over the data updating the objects
// with the totals found in the lookup object
for (let obj of data) {
lookup[obj.no] && out.push({
no: obj.no,
total: lookup[obj.no]
});
}
document.querySelector('#lookup').textContent = JSON.stringify(lookup, null, 2);
document.querySelector('#out').textContent = JSON.stringify(out, null, 2);
<h3>Lookup output</h3>
<pre id="lookup"></pre>
<h3>Main output</h3>
<pre id="out"></pre>
Perhaps something like this? You can map the existing data array and attach filtered array counts to each array object.
let data = [
{
no: 3,
name: 'drink'
},
{
no:90,
name: 'eat'
},
{
no:20,
name: 'swim'
}
]
const test = [3,3,3,3,3,3,3,3,3,3,3,90,20,20,20,20]
const result = data.map((item) => {
return {
num: item.no,
total: test.filter(i => i === item.no).length // filters number array and then checks length
}
})
You can check next approach using a single for/of loop. But first I have to create a Set with valid ids, so I can discard noise data from the test array:
const data = [
{no: 3, name: 'drink'},
{no: 90, name: 'eat'},
{no: 20, name: 'swim'}
];
const userArr = [3,3,3,3,3,3,3,3,7,7,9,9,3,3,3,90,20,20,20,20];
let ids = new Set(data.map(x => x.no));
let newArr = [];
for (i of userArr)
{
let found = newArr.findIndex(x => x.num === i)
if (found >= 0)
newArr[found].total += 1;
else
ids.has(i) && newArr.push({num: i, total: 1});
}
console.log(newArr);

Categories