How to sum value of diffrent arrays in Arrays Of Objects - javascript

I'm trying to sum the values of arrays inside an array.
const arr = [
{ key: 0, x: [4,5,6], y: [1,2,3,4]},
{ key: 0, x: [1], y: [] }
]
The expected output would be 26 ( 4 + 5 + 6 + 1 + 2 ...)
No idea how to do this, tried with reduce but I don't know how to access the other array.
Any help would be great.

You can try getting the sum of nested object's array first, then sum them up and return like the following way:
const arr = [
{ key: 0, x: [4,5,6], y: [1,2,3,4]},
{ key: 0, x: [1], y: [] }
]
const sum = arr.reduce((a, c) => {
const cTemp = Object.values(c).flat().reduce((aa,cc) => aa+cc, 0);;
return a + cTemp;
}, 0);
console.log(sum);

const total = [
{key: 0, x: [4, 5, 6], y: [1, 2, 3, 4]},
{key: 0, x: [1], y: []},
]
.map(({x, y}) => [...x, ...y])
.reduce((total, curr) => total + curr.reduce((a, b) => a + b), 0);
const total = [
{key: 0, x: [4, 5, 6], y: [1, 2, 3, 4]},
{key: 0, x: [1], y: []},
]
.map(({x, y}) => [...x, ...y])
.reduce((total, curr) => total + curr.reduce((a, b) => a + b), 0);
console.log(total);

No idea how to do this, tried with reduce but I don't know how to
access the other array.
You can create another function named sum to sum all values in an array. After that, at each object, you can use Spread ... to merge 2 arrays into one like this.
const arr = [ { key: 0, x: [4,5,6], y: [1,2,3,4]},
{ key: 0, x: [1], y: [] }];
const sum = (arr) => arr.reduce((acc, curr) => acc+= curr, 0);
const result = arr.reduce((acc, {x, y}) => acc += sum([...x, ...y]), 0);
console.log(result);
Another way is to use Array#flatMap to get all values, then use Array#reduce to sum them.
const allValues = arr.flatMap(({x, y}) => [...x, ...y]);
const result = allValues.reduce((acc, curr) => acc+= curr, 0);
const arr = [ { key: 0, x: [4,5,6], y: [1,2,3,4]},
{ key: 0, x: [1], y: [] }];
const allValues = arr.flatMap(({x, y}) => [...x, ...y]);
const result = allValues.reduce((acc, curr) => acc+= curr, 0);
console.log(result);
The flatMap() method returns a new array formed by applying a given
callback function to each element of the array, and then flattening
the result by one level

This works for me.
const arr = [{
key: 0,
x: [4, 5, 6],
y: [1, 2, 3, 4]
},
{
key: 0,
x: [1],
y: []
}
]
var total = 0;
arr.forEach(function(value) {
value.x.forEach(function(x) {
total += x;
});
value.y.forEach(function(y) {
total += y;
});
});
console.log(total);

Related

How can i improve this Javascript code that arrange the array in ordered list first and put them in an array of array with same value?

Can this code be Improved? It arrange our array into sorted list(sortedArray) first and, the finalArray takes the final result;Example finalArray = [[1,1,1,1][2,2,2]...]
let array = [1, 2, 4, 591, 392, 391, 2, 5, 10, 2, 1, 1, 1, 20, 20]
let sortedArray = []
let finalArray = []
sortedArray = array.sort((a, b) => {
if (a > b) return 1;
if (a < b) return -1;
return sortedArray.push(a - b);
});
finalArray = sortedArray.reduce((item, index) => {
if (typeof item.last === 'undefined' || item.last !== index) {
item.last = index;
item.sortedArray.push([]);
}
item.sortedArray[item.sortedArray.length - 1].push(index);
return item;
}, {
sortedArray: []
}).sortedArray;
console.log(finalArray);
Here is a shorter version than yours and more readable than Nina's
let array = [1, 2, 4, 591, 392, 391, 2, 5, 10, 2, 1, 1, 1, 20, 20]
const finalArray = array.slice(0) // copy the array
.reduce((acc,cur) => {
const idx = acc.findIndex(item => item[0] === cur);
if (idx !=-1) acc[idx].push(cur); // just push
else acc.push([cur]); // push as array
return acc
},[])
.sort(([a],[b]) => a-b); // sort on the first entry
console.log(finalArray);
You could group first and then sort by the first item of each array.
If you have only positive 32 bit intger values, you could omit sorting, because the object is sorted like an array.
const
array = [1, 2, 4, 591, 392, 391, 2, 5, 10, 2, 1, 1, 1, 20, 20],
result = Object
.values(array.reduce((r, v) => {
(r[v] ??= []).push(v);
return r;
}, {}))
.sort(([a], [b]) => a - b);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Transform array of keys and array of values into array of objects javascript

My question is quite similar to this one: Merge keys array and values array into an object in JavaScript
However, I don't seem to find the solution for my example. If I have these two arrays:
const keys = ['x', 'y', 'z'];
const values = [
[0, 1, 2],
[10, 20, 30],
];
How do I combine them into an array of objects, such that would be the expected result?
[
{
x: 0,
y: 1,
z: 2,
},
{
x: 10,
y: 20,
z: 30,
},
]
You can use Array.prototype.map() and Array.prototype.reduce() for this:
const keys = ['x', 'y', 'z'];
const values = [
[0, 1, 2],
[10, 20, 30],
];
const res = values.map(arr => arr.reduce((acc, curr, index) => {
acc[keys[index]] = curr
return acc;
}, {x: null, y: null, z: null}));
console.log(res);
Or you can also do it without reduce() like so:
const res = values.map(arr => ({
[keys[0]]: arr[0],
[keys[1]]: arr[1],
[keys[2]]: arr[2]
}));
Cycle through the value arrays and create an object for each, then cycle through the values within those arrays and use the keys array as the keys.
const keys = ['x', 'y', 'z'];
const values = [
[0, 1, 2],
[10, 20, 30],
];
const output = [];
values.forEach((v, i) => {
output[i] = {}; // create objects for each of the value arrays
v.forEach((w, j) => {
output[i][keys[j]] = w; // use the correct keys with each of the values
});
});
console.log(output);
As comments have also pointed out, this can be done with Array.reduce:
const keys = ['x', 'y', 'z'];
const values = [
[0, 1, 2],
[10, 20, 30],
];
const output = values.map(x => { // for each of the values arrays
return x.reduce((a, c, i) => { // take its values
a[keys[i]] = c // map them to an object property one by one
return a; // put them together in the same object.
}, {});
});
console.log(output);
const keys = ['x', 'y', 'z'];
const values = [
[0, 1, 2],
[10, 20, 30],
];
function toObject(keys, values) {
let final = []
for (let i = 0; i < values.length; i++){
let result = {};
for(let j=0;j<keys.length;j++){
result[keys[j]] = values[i][j];
}
final.push(result)
}
return final
console.log(final)
}
toObject(keys,values )
it will work

Building an array of sequential numbers

i have an incoming array:
[{step: 0, count: 1}, {step: 1, count: 5}, {step: 5, count: 5}]
so i need to transform incoming array in another array
[0, 1, 2, 3, 4, 5, 10, 15, 20, 25, 30]
I have tried to go this way:
const convertRangeData = (rangeData) =>
{
const convertedRangeData =
rangeData.reduce( (acc, item) =>
{
const { step, count } = item;
const prev = acc[acc.length - 1];
return [...acc, ...[...Array(count)].fill(step).map((i, idx) => i * (idx + 1) + prev)];
},[0] )
return convertedRangeData;
}
but I've got
[0, 0, 1, 2, 3, 4, 5, 10, 15, 20, 25, 30]
Use Array.from() to create an array with values in the ranges. Then iterate the array of ranges.
To create the continuous ranges reduce the array of ranges. When creating a range take the last number from the accumulator (acc), and use it as the start value.
const range = ({ step, count }, start = 0) =>
Array.from({ length: count }, (_, i) => (i + 1) * step + start)
const continuousRange = arr =>
arr.reduce((acc, r) => acc.concat(range(r, acc[acc.length -1])), [])
const ranges = [{step: 0, count: 1}, {step: 1, count: 5}, {step: 5, count: 5}]
const result = continuousRange(ranges)
console.log(result)
my way
const ranges = [{step: 0, count: 1}, {step: 1, count: 5}, {step: 5, count: 5}]
const convertRangeData = rangeData => rangeData.reduce((acc, {step,count}) =>
{
let prev = acc[acc.length - 1] || 0
while(count--)
acc.push(prev+=step)
return acc
},[])
console.log( convertRangeData(ranges) )

How to count duplicate object in JS

im trying to add counting number for duplicate in JS.
and i am completely stack in this case below.
i need to compare objects with two value (x, y) and if there are same values of (x, y) add count 1 on new objects.
is there any way to convert data to newData such as below?
const data = [
{id: 1, x: 1, y: 1},
{id: 2, x: 2, y: 2},
{id: 3, x: 1, y: 1},
]
const newData = [
{x: 1, y:1 ,count:2}
{x: 2, y:2 ,count:1}
]
use .reduce() function
const data = [
{id: 1, x: 1, y: 1},
{id: 2, x: 2, y: 2},
{id: 3, x: 1, y: 1},
]
const output = data.reduce((acc, curr) => {
curr.count = 1;
const exists = acc.find(o => o.x === curr.x && o.y === curr.y);
exists ? exists.count++ : acc.push(({ x, y, count } = curr));
return acc;
}, []);
console.log(output);
.as-console-wrapper { max-height: 100% !important; top: 0; }
One way of doing so, is to create a map with the x and y values, and increment the count accordingly, then convert the map into an array:
const data = [
{id: 1, x: 1, y: 1},
{id: 2, x: 2, y: 2},
{id: 3, x: 1, y: 1},
]
const makeXYMap = (data) => data.reduce((acc, cur) => {
const { x, y } = cur;
const entry = acc[`${x}_${y}`];
if (entry) {
acc[`${x}_${y}`] = {...entry, count: entry.count + 1};
} else {
acc[`${x}_${y}`] = { x, y, count: 1 };
}
return acc;
}, {});
const makeArray = (XYMap) => Object.values(XYMap);
console.log(makeArray(makeXYMap(data)));
Note that complexity wise, this solution is a O(N).
https://jsfiddle.net/9o35neg7/
const data = [
{ id: 1, x: 1, y: 1 },
{ id: 2, x: 2, y: 2 },
{ id: 3, x: 1, y: 1 },
// .. so on ..
];
const countedData = data.reduce((acc, { x, y }, index, array) => {
acc[`x${x}y${y}`] = {
x,
y,
count: (acc[`x${x}y${y}`] ? acc[`x${x}y${y}`].count : 0) + 1
};
return index === (array.length - 1) ? Object.values(acc) : acc;
}, {});
console.log(countedData);
Use forEach and build an object with key (made of x, y) and values (aggregate count). Get the Object.values to get the results as array.
const data = [
{id: 1, x: 1, y: 1},
{id: 2, x: 2, y: 2},
{id: 3, x: 1, y: 1},
]
const counts = (arr, res = {}) => {
arr.forEach(({x , y}) =>
res[`${x}-${y}`] = { x, y, count: (res[`${x}-${y}`]?.count ?? 0) + 1 })
return Object.values(res);
}
console.log(counts(data))

How do I return 2 values from two arrays when using filter

I have a Javascript code that uses forEach to loop through each array to check if it fulfils a condition. Then, it calls for another function. Note:
by looping through every element in arr1 and arr2, I'm checking if any elements in arr1 are colliding with any elements in arr2. isCollision is a function which calculates their distance if they intersect
arr1.forEach(x => arr2.forEach(y => isCollision(x,y)? explode(x,y): undefined));
Right now, I do not want it to return undefined. So I was wondering is there a way to get the x & y values so that I can map it to another function. I tried this
arr1.filter(x => arr2.filter(y => isCollision(x,y)).map(x,y => //do something)
But right now it's only returning the value of y. Is there a way for it to return both x and y?
Try this:
arr1
.map(x => ({x, y:arr2.find(y => isCollision(x,y)}))
.filter(pair => pair.y !== undefined)
First map to {x:y} and then remove not found items.
To cast to a non-undefined type, use a another map.
arr1
.map(x => ({x, y:arr2.find(y => isCollision(x,y)}))
.filter(pair => pair.y !== undefined)
.map(pair => pair as {x:Elem, y:Elem})
If you want to find all pairs of objects from arr1 and arr2 that match some requirement (isCollision) using only array methods, that's probably not going to be as pretty as doing a pair of loops. But still, it's doable - the basic idea is that you want to check each pair of objects from arr1 and arr2 against your isCollision. And to do that you need to go over all possible combinations between the two arrays. So, the basic steps are:
Generate all combinations of pairs from the two arrays
Filter the pairs by using isCollision
Anything you get will be colliding, so you can run whatever you want with those.
So, here is a simplified representation of the objects - they only have a coord property which shows their position (one dimensional for simplicity) and a value property. isCollision checks if any two objects take the exact same space. Your logic and objects would be different but that should't matter for the execution steps you need to take
const arr1 = [
{ coord: 1, value: "x1" },
{ coord: 2, value: "x2" },
{ coord: 3, value: "x3" },
{ coord: 4, value: "x4" },
{ coord: 5, value: "x5" }
];
const arr2 = [
{ coord: 2, value: "y2" },
{ coord: 4, value: "y4" }
];
function isCollision(x, y) {
return x.coord === y.coord;
}
function explode(x, y) {
console.log(`${x.value} explodes, as does ${y.value}`);
}
arr1
.flatMap(x => arr2.map(y => [x, y])) //1. generate all combinations of pairs
.filter(pair => isCollision(...pair)) //2. get only the colliding objects
.forEach(pair => explode(...pair)); //3. run them through the explode() function
Here, I use Array#flatMap to generate pairs - the function given to flatMap will generate an array of pairs itself, so if we just had .map, that will return
[
[[x1, y2], [x1, y4]],
[[x2, y2], [x2, y4]],
[[x3, y2], [x3, y4]],
[[x4, y2], [x4, y4]],
[[x5, y2], [x5, y4]]
]
instead of
[
[x1, y2],
[x1, y4],
[x2, y2],
[x2, y4],
[x3, y2],
[x3, y4],
[x4, y2],
[x4, y4],
[x5, y2],
[x5, y4]
]
Inside Array#filter and Array#forEach the spread syntax is used to turn the pair of objects into arguments to the functions.
This can be be slightly more elegant by using array destructuring for the parameters of the functions:
const arr1 = [
{ coord: 1, value: "x1" },
{ coord: 2, value: "x2" },
{ coord: 3, value: "x3" },
{ coord: 4, value: "x4" },
{ coord: 5, value: "x5" }
];
const arr2 = [
{ coord: 2, value: "y2" },
{ coord: 4, value: "y4" }
];
function isCollision([x, y]) { //<-- destructuring
return x.coord === y.coord;
}
function explode([x, y]) { //<-- destructuring
console.log(`${x.value} explodes, as does ${y.value}`);
}
arr1
.flatMap(x => arr2.map(y => [x, y]))
.filter(isCollision) // <--------------------------------------|
.forEach(explode);// <-- just passing the function reference --|
Anything you do will have the same complexity, since you still need to iterate through each of arr1 and arr2 anyway - you could only .flatMap directly only collisions, skipping the .filter step...but that just means that you need to do the .filter as part of the flatmap. So, this shows off all operations you'd need to do.
In this case, it might be easier to just keep your original code. It might look slightly less elegant in some ways but it works and it still does the same steps - goes through each pair of x, y, checks if the pair collides and it executes a function if it does.
const arr1 = [
{ coord: 1, value: "x1" },
{ coord: 2, value: "x2" },
{ coord: 3, value: "x3" },
{ coord: 4, value: "x4" },
{ coord: 5, value: "x5" }
];
const arr2 = [
{ coord: 2, value: "y2" },
{ coord: 4, value: "y4" }
];
function isCollision(x, y) {
return x.coord === y.coord;
}
function explode(x, y) {
console.log(`${x.value} explodes, as does ${y.value}`);
}
arr1
.forEach(x => arr2.forEach(y => {
if (isCollision(x,y)) {
explode(x,y)
}
}));
You could use reduce() instead of: filter() + map().
So you donĀ“t have the 2nd loop of chaining methods:
let a1 = [
{ x: 1, y: "y1" },
{ x: 2, y: "y2" },
{ x: 3, y: "y3" },
{ x: 4, y: "y4" },
{ x: 5, y: "y5" }
];
let a2 = [
{ x: 2, y: "y2" },
{ x: 4, y: "y4" },
{ x: 7, y: "y7" }
];
let isCollision = (
{x: x1, y: y1},
{x: x2, y: y2}
) => x1 === x2 && y1 === y2;
// Custom logic:
let explode = ({x, y}) => console.log(`Explode {x: %d, y: %o}`, x, y) || {x,y};
// You could use .reduce() instead of .filter().map() combo:
let collisions = a1.reduce((acc, p1) => a2.some(p2 => isCollision(p1, p2)) ? [...acc, explode(p1)] : acc, []);
// Explode {x: 2, y: "y2"}
// Explode {x: 4, y: "y4"}

Categories

Resources