javascript calculation of person ages and heights - javascript

I need to take sum of all the person's ages and heights.
Input Array:
[
{
"personId": 1,
"ages": [
1,
4,
5
],
"heights": [
1,
1,
2
]
},
{
"personId": 2,
"ages": [
4,
2,
2
],
"heights": [
1,
4,
2
]
},
{
"personId": 2,
"ages": [
2,
1,
1
],
"heights": [
12
]
}
]
Desired Output:
[
{
"type": "ages",
"values": 22
},
{
"type": "heights",
"values": 23
}
]
My Solution (Which is working perfectly fine):
var agesTotal = 0;
var heightsTotal = 0;
var resultArr = [];
var sourceArr = [{personId: 1, ages: [1,4,5], heights: [1,1,2]}, {personId: 2, ages: [4,2,2], heights: [1,4,2]}, {personId: 2, ages: [2,1,1], heights: [12]}];
for(var i = 0; i < sourceArr.length; i++){
if(sourceArr[i].ages){
if(i == 0){
resultArr.push({
type: "ages",
values: agesTotal
});
}
for(var n = 0; n < resultArr.length; n++){
if(resultArr[n].type == "ages"){
resultArr[n].values += agesTotal + sourceArr[i].ages.reduce((partialSum, a) => parseFloat(partialSum) + parseFloat(a), 0)
}
}
}
if(sourceArr[i].heights){
if(i == 0){
resultArr.push({
type: "heights",
values: heightsTotal
});
}
for(var n = 0; n < resultArr.length; n++){
if(resultArr[n].type == "heights"){
resultArr[n].values += heightsTotal + sourceArr[i].heights.reduce((partialSum, a) => parseFloat(partialSum) + parseFloat(a), 0)
}
}
}
}
This above code of mine is producing the correct response, but it seems like so much processing and unoptimized.
What I need is the best & optimized possible solution for this operation

Without a clearly defined performance objective, it's hard to provide an answer that I feel is satisfying. However, I think this is readable, concise, and not wasteful:
function sumArrays (accumulator, obj) {
for (const [key, value] of Object.entries(obj)) {
if (!Array.isArray(value)) continue;
accumulator[key] ??= 0;
for (const n of value) accumulator[key] += n;
}
}
function getSums (array) {
const accumulator = {};
for (const obj of array) sumArrays(accumulator, obj);
return Object.entries(accumulator).map(([type, values]) => ({type, values}));
}
// Or, instead, optimized only for the input keys:
function getSumsOptimized (array, keysToSum) {
const result = keysToSum.map(type => ({type, values: 0}));
for (const obj of array) {
for (const [index, key] of keysToSum.entries()) {
for (const n of obj[key]) result[index].values += n;
}
}
return result;
}
const input = [
{ personId: 1, ages: [1, 4, 5], heights: [1, 1, 2]},
{ personId: 2, ages: [4, 2, 2], heights: [1, 4, 2]},
{ personId: 2, ages: [2, 1, 1], heights: [12 ]},
];
console.log(getSums(input));
console.log(getSumsOptimized(input, ['ages', 'heights']));

const array = [
{
"personId": 1,
"ages": [
1,
4,
5
],
"heights": [
1,
1,
2
]
},
{
"personId": 2,
"ages": [
4,
2,
2
],
"heights": [
1,
4,
2
]
},
{
"personId": 2,
"ages": [
2,
1,
1
],
"heights": [
12
]
}
]
let heightsSum = 0;
let agesSum = 0;
array.forEach(element => {
element.ages.forEach(age => {
agesSum += age;
})
element.heights.forEach(height => {
heightsSum += height;
})
})
const arr = [
{
type: 'ages',
values: agesSum
},
{
type: 'heights',
values: heightsSum
}
]
console.log(arr)

Related

Confused about pushing array into array, JavaScript

My code looks like this
var res = [];
var temp = [];
function Permutations(target, size) {
if (size === 0) {
res.push(temp);
console.log(res);
return;
}
for (let i = 0; i < target.length; i++) {
if (target[i] !== null) {
temp.push(target[i]);
target[i] = null;
Permutations(target, size - 1);
target[i] = temp.pop();
}
}
}
Permutations([1, 2, 3], 2);
console.log(res);
When I run my code, I can see my res stores each permutation as it is is being executed. However, when I log it outside the function, all the stored value disappeared.
[ [ 1, 2 ] ]
[ [ 1, 3 ], [ 1, 3 ] ]
[ [ 2, 1 ], [ 2, 1 ], [ 2, 1 ] ]
[ [ 2, 3 ], [ 2, 3 ], [ 2, 3 ], [ 2, 3 ] ]
[ [ 3, 1 ], [ 3, 1 ], [ 3, 1 ], [ 3, 1 ], [ 3, 1 ] ]
[ [ 3, 2 ], [ 3, 2 ], [ 3, 2 ], [ 3, 2 ], [ 3, 2 ], [ 3, 2 ] ]
[ [], [], [], [], [], [] ] // This is my console.log outside the function
The array temp holds is the same array throughout the complete execution of your code. And res.push(temp); adds this same array (not a copy of it) to your res array.
Here a related question about how Objects are handled in JavaScript: Is JavaScript a pass-by-reference or pass-by-value language?
So your code results in res having N times the same array.
You could copy the element stored in temp to a new array using [...temp], and push that to your res array.
var res = [];
var temp = [];
function Permutations(target, size) {
if (size === 0) {
res.push([...temp]);
return;
}
for (let i = 0; i < target.length; i++) {
if (target[i] !== null) {
temp.push(target[i]);
target[i] = null;
Permutations(target, size - 1);
target[i] = temp.pop();
}
}
}
Permutations([1, 2, 3], 2);
console.log(res);

Find common values between two array of objects and store as array of objects

I have two array of objects
const oldArr = [
{
assetDetail_ID: 1,
asset_Condition: "",
asset_Condition_ID: 0,
supplier_ID: 5,
},
{
assetDetail_ID: 2,
asset_Condition: "Good",
asset_Condition_ID: 3,
supplier_ID: 10,
},
];
const newArr = [
{
assetDetail_ID: 1,
supplier_ID: 40,
},
{
assetDetail_ID: 2,
supplier_ID: 30,
},
];
I am trying find common values by checking with object key and if they are the same, get key and value pair into a new array so my final result will be
expectedResult = [
{
assetDetail_ID: 1,
supplier_ID: 5,
},
{
assetDetail_ID: 2,
supplier_ID: 10,
},
];
I have tried this but I am only getting values as [1, 5, 2, 10]and not objects , what am I doing wrong here ?
const oldArr = [{
assetDetail_ID: 1,
asset_Condition: "",
asset_Condition_ID: 0,
supplier_ID: 5,
},
{
assetDetail_ID: 2,
asset_Condition: "Good",
asset_Condition_ID: 3,
supplier_ID: 10,
},
];
const newArr = [{
assetDetail_ID: 1,
supplier_ID: 40,
},
{
assetDetail_ID: 2,
supplier_ID: 30,
},
];
const arr = []
oldArr.forEach((one, x) => {
for (let i in one) {
for (let j in newArr[x])
if (i === j) {
arr.push(one[i]); // If I change to arr.push(one);, it adds the whole object
}
}
});
console.log(arr)
if you want to do it your way,
const oldArr = [{
assetDetail_ID: 1,
asset_Condition: "",
asset_Condition_ID: 0,
supplier_ID: 5,
},
{
assetDetail_ID: 2,
asset_Condition: "Good",
asset_Condition_ID: 3,
supplier_ID: 10,
},
];
const newArr = [{
assetDetail_ID: 1,
supplier_ID: 40,
},
{
assetDetail_ID: 2,
supplier_ID: 30,
},
];
const arr = oldArr.map((one, index) => {
const existingKeys = Object.keys(newArr[index]).filter(key => one.hasOwnProperty(key));
let newObj = existingKeys.reduce((acc, curr) => {
acc[curr] = one[curr];
return acc;
}, {});
return newObj;
});
console.log(arr)
You could take a single loop approach for both arrays and collect all assetDetail_ID of newArr in an object and get a flat array from oldArr by returning either a new object or an empty array.
const
oldArr = [{ assetDetail_ID: 1, asset_Condition: "", asset_Condition_ID: 0, supplier_ID: 5 }, { assetDetail_ID: 2, asset_Condition: "Good", asset_Condition_ID: 3, supplier_ID: 10 }],
newArr = [{ assetDetail_ID: 1, supplier_ID: 40 }, { assetDetail_ID: 2, supplier_ID: 30 }],
temp = Object.fromEntries(newArr.map(({ assetDetail_ID }) => [assetDetail_ID, true])),
result = oldArr.flatMap(({ assetDetail_ID, supplier_ID }) => temp[assetDetail_ID]
? { assetDetail_ID, supplier_ID }
: []
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
function doTheJob(oldArr, newArr){
let result = new Set();
for(let i = 0; i < oldArr.length; i++){
for(let j = 0; j < newArr.length; j++){
if(oldArr[i].assertDetail_ID === newArr[j].assertDetail_ID){
result.add(newArr[j]);
}
}
}
return Array.from(result);
}
This can solve your problem!
What you need is classic JavaScript array function filter()
Here's an example -
//your array
const oldArr = [
{
assetDetail_ID: 1,
asset_Condition: "",
asset_Condition_ID: 0,
supplier_ID: 5,
},
{
assetDetail_ID: 2,
asset_Condition: "Good",
asset_Condition_ID: 3,
supplier_ID: 10,
},
];
The function -
function getArr(id){
const newArr = oldArr.filter(obj => { return obj.assetDetail_ID === id})
console.log(newArr); //let id = 1; this will give you a sub-array where assetDetail_ID = 1
return newArr;
}

How to dynamically build a javascript Object and push into Array within nested loop?

I'm trying to dynamically build Objects and push them one by one into an Array.
My code so far is this:
matrix([[0,1,1], [1,00], [1,1,1])
const matrix = (sequence) => {
const rows = {}
const rowsAry = []
let row
let idx
for (let i=0; i < samples.length; i++) {
row = `row${i}`
for (let j=0; j < samples[i].length; j++) {
if (samples[i][j] === 1) {
idx = []
rows[row] = rows[row] + 1 || 1
rows['indeces'] = idx.push(j)
rowsAry.push(rows)
}
}
}
console.log(rowsAry)
}
This obviously isn't working. I'm trying to map out all the '1's' in the sequence and know how many are in a row and what there indices are.
The wrong out put is:
[ { row0: 3, indeces: 1, row1: 2, row2: 2 },
{ row0: 3, indeces: 1, row1: 2, row2: 2 },
{ row0: 3, indeces: 1, row1: 2, row2: 2 },
{ row0: 3, indeces: 1, row1: 2, row2: 2 },
{ row0: 3, indeces: 1, row1: 2, row2: 2 },
{ row0: 3, indeces: 1, row1: 2, row2: 2 },
{ row0: 3, indeces: 1, row1: 2, row2: 2 },
{ row0: 3, indeces: 1, row1: 2, row2: 2 },
{ row0: 3, indeces: 1, row1: 2, row2: 2 } ]
Hoped for output would be:
[{row1: 2, indices: [1,2]},
{row2: 1, indices: [0]},
{row3: 3, indices: [0,1,2]}
]
You need to create a new object each time through the outer loop. And only push it onto rowsAry once, not each time through the inner loop.
const matrix = (samples) => {
const rowsAry = []
for (let i = 0; i < samples.length; i++) {
let row = `row${i}`
let indices = [];
for (let j = 0; j < samples[i].length; j++) {
if (samples[i][j] === 1) {
indices.push(j);
}
}
rowsAry.push({[row]: indices.length, indices: indices});
}
console.log(rowsAry)
}
matrix([
[0, 1, 1],
[1, 00],
[1, 1, 1]
])
You can solve it by simply using array map and forEach method. Traverse the array of arrays and check for ones to the inside array by using array forEach method and if found put it to the resultant array. At last, using the resultant array make your required object.
const matrix = (sequence) => {
return sequence.map((x, i) => {
const ret = [];
x.forEach((y, j) => {
if (y === 1) ret.push(j);
});
const key = `row${i + 1}`;
const obj = { [key]: ret.length, indices: ret };
return obj;
});
};
const ret = matrix([
[0, 1, 1],
[1, 0, 0],
[1, 1, 1],
]);
console.log(ret);
Or nested reduce() calls...
const matrix = (sequence) => {
return sequence.reduce((a, r, i) => {
indices = r.reduce((ra, rn, ri) => {
if (rn === 1) ra.push(ri);
return ra;
}, []);
a.push({[`row${i}`]: indices.length, indices: indices});
return a;
}, []);
}
console.log(matrix([[0,1,1], [1,0,0], [1,1,1]]))
But in reference to Barmar's comment about using different rowX keys a more accessible shape for your objects might look something along the lines of
{row: 1, count: 2, indices: [1, 2]}

How to reduce array of objects based on common key values?

Let's say, I have an Array of object which looks like:
var jsonData = [
{"DS01":123,"DS02":88888,"DS03":1,"DS04":2,"DS05":3,"DS06":666},
{"DS01":123,"DS02":88888,"DS03":2,"DS04":3,"DS05":4,"DS06":666},
{"DS01":124,"DS02":99999,"DS03":3,"DS04":4,"DS05":5,"DS06":333},
{"DS01":124,"DS02":99999,"DS03":5,"DS04":6,"DS05":7,"DS06":333}
];
You can see there are some common key fields which are DS01, DS02 and DS06. Firstly, I want to find which are common group of keys.
For first 2 Objects : DS01 = 123, DS02 = 88888, DS06 = 666
For last 2 Objects : DS01 = 124, DS02 = 99999, DS06 = 333
I want to convert this array of objects to a format like this:
var jsonDataReduced =
[{
"DS01": 123,
"DS02": 88888,
"DS03": [1, 2],
"DS04": [2, 3],
"DS05": [3, 4],
"DS06": 666
},
{
"DS01": 124,
"DS02": 99999,
"DS03": [3, 5],
"DS04": [4, 6],
"DS05": [5, 7],
"DS06": 333
}
];
Let's say, I have another array of objects.
var jsonData2 = [{
"Mass": 3,
"Force": 3.1,
"Acceleration": 4
}, {
"Mass": 3,
"Force": 4.1,
"Acceleration": 4
}];
So after reducing it should be:
var jsonData2 = [{
"Mass": 3,
"Force": [3.1, 4.1],
"Acceleration": 4
}];
I have been trying to do these by using Array.reduce() but not getting an idea on how to do this job efficiently.
Is it possible to
making a single function
passing these kinds of array of objects as a parameter
and finally getting the reduced dataset
What I have tried :
var jsonData2 = [{
"Mass": 3,
"Force": 3.1,
"Acceleration": 4
}, {
"Mass": 3,
"Force": 4.1,
"Acceleration": 4
}];
const reduced = jsonData2.reduce((r, e, i, a) => {
if (i % 2 == 0) {
const next = a[i + 1];
const obj = { ...e, Force: [e.Force] }
if (next) obj.Force.push(next.Force);
r.push(obj)
}
return r;
}, []);
console.log(reduced);
You could get common keys and group by them.
var data = [{ DS01: 123, DS02: 88888, DS03: 1, DS04: 2, DS05: 3, DS06: 666 }, { DS01: 123, DS02: 88888, DS03: 2, DS04: 3, DS05: 4, DS06: 666 }, { DS01: 124, DS02: 99999, DS03: 3, DS04: 4, DS05: 5, DS06: 333 }, { DS01: 124, DS02: 99999, DS03: 5, DS04: 6, DS05: 7, DS06: 333 }],
common,
temp = data.reduce((r, o, i) => {
Object.entries(o).forEach(([k, v]) => {
r[k] = r[k] || [];
r[k][i] = v;
});
return r;
}, {}),
min = Infinity,
result;
Object.entries(temp).forEach(([k, a]) => {
var s = new Set;
temp[k] = a.map(v => s.add(v).size);
min = Math.min(min, s.size);
});
common = Object.keys(temp).filter(k => temp[k][temp[k].length - 1] === min);
result = data.reduce((r, o) => {
var temp = r.find(q => common.every(k => q[k] === o[k]));
if (!temp) {
r.push({ ...o });
} else {
Object.keys(o).filter(k => !common.includes(k)).forEach(k => Array.isArray(temp[k]) ? temp[k].push(o[k]) : (temp[k] = [temp[k], o[k]]));
}
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

add properties of object in array and get single object by loadash

I am using loadash in my project
i have object in array like this
[{
"rating": {
"time_to_table": 5,
"value_for_money": 5,
"innovation": 5,
"plating_decoration": 5,
"taste": 5
}
}, {
"rating": {
"time_to_table": 0,
"value_for_money": 3,
"innovation": 2,
"plating_decoration": 2,
"taste": 4
}
}]
Now I want output like this by adding each property and want single object like this
"rating": {
"time_to_table": 5,
"value_for_money": 8,
"innovation": 7,
"plating_decoration": 7,
"taste": 9
}
I have tried this
var obj = {
"time_to_table": 0,
"value_for_money": 0,
"innovation": 0,
"plating_decoration": 0,
"taste": 0,
"total" : 5 * data.length
}
_.forEach(data,function(d){
obj.time_to_table += d.rating.time_to_table;
obj.value_for_money += d.rating.value_for_money;
obj.innovation += d.rating.innovation;
obj.plating_decoration += d.rating.plating_decoration;
obj.taste += d.rating.taste;
});
With Lodash you can do this using reduce() and mergeWith() that takes custom function as parameter.
var data = [{"rating":{"time_to_table":5,"value_for_money":5,"innovation":5,"plating_decoration":5,"taste":5}},{"rating":{"time_to_table":0,"value_for_money":3,"innovation":2,"plating_decoration":2,"taste":4}}]
var result = _.reduce(data, function(r, e, i) {
if(i != 0) _.mergeWith(r.rating, e.rating, (a, b) => a + b)
return r;
}, data[0])
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
You can use reduce, and having as many property as you want in your objects.
The following function doesn't require to know anything about the kind of object you are passing, because there are no hardcoded properties
const arr = [{
"rating": {
"time_to_table": 5,
"value_for_money": 5,
"innovation": 5,
"plating_decoration": 5,
"taste": 5
},
a: {b: 1, c: 2}
}, {
"rating": {
"time_to_table": 0,
"value_for_money": 3,
"innovation": 2,
"plating_decoration": 2,
"taste": 4
},
a: {b: 3, c: 0}
}];
const result = arr.reduce(fn, {})
function fn (acc, val) {
for (let x in val) {
acc[x] = acc[x] || {};
for (let y in val[x]) {
acc[x][y] = acc[x][y] || 0;
acc[x][y] += val[x][y];
}
}
return acc;
}
console.log(result)
Array#reduce solution.
var arr = [{"rating":{"time_to_table":5,"value_for_money":5,"innovation":5,"plating_decoration":5,"taste":5}},{"rating":{"time_to_table":0,"value_for_money":3,"innovation":2,"plating_decoration":2,"taste":4}}], obj = arr[0]; arr.splice(0,1);
var res = arr.reduce(function(s, a) {
Object.keys(a.rating).forEach(function(v) {
s.rating[v] += a.rating[v];
})
return s;
}, obj);
console.log(res);
You can do it using Array#reduce() and Object.keys()
const data = [{rating:{time_to_table:5,value_for_money:5,innovation:5,plating_decoration:5,taste:5}},{rating:{time_to_table:0,value_for_money:3,innovation:2,plating_decoration:2,taste:4}}];
let finalObject = data.reduce((o, c) => {
Object.keys(c.rating).forEach(k => {
o.rating[k] = o.rating[k] || 0;
o.rating[k] += c.rating[k];
});
return o;
}, { rating: {} })
console.log(finalObject);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could use a recursive approach for arbitrary nested object, to collect and sum values in the objects.
var data = [{ rating: { time_to_table: 5, value_for_money: 5, innovation: 5, plating_decoration: 5, taste: 5 } }, { rating: { time_to_table: 0, value_for_money: 3, innovation: 2, plating_decoration: 2, taste: 4 } }],
result = data.reduce(function iter(target, source) {
Object.keys(source).forEach(function (k) {
if (source[k] && typeof source[k] === 'object') {
iter(target[k] = target[k] || {}, source[k]);
return;
}
target[k] = (target[k] || 0) + +source[k];
});
return target;
}, {});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Categories