I am trying to add 4 nested arrays with 9 numeric values together in javascript and having issues. They are currently stored like: x = [[Array1(9)], [Array2(9)], [Array3(9)], [Array4(9)]]
I would like "zip" them together and add in the process so adding Array1[0] with Array2-4[0] to all nine values. So each of the four arrays summing up their matching ids.
Arrays look like this:
[1, 2, 4, 3.6, 1.05, 4.65, 1.95, 0.5, 2.5]
[0.432, 0.602, 1.29, 1.146, 0.558, 1.43, 0.686, 0.178, 1.024]
translating to:
[1.432, 2.602, ect...]
I can't seem to get a x.map() function to put them together the way I want. Any help would be appreciated.
Thanks,
You may traverse your outer array with Array.prototype.reduce() and loop through nested arrays one by one with Array.prototype.forEach() adding up nested array items to corresponding item of resulting array:
const src = [[1, 2, 4, 3.6, 1.05, 4.65, 1.95, 0.5, 2.5], [0.432, 0.602, 1.29, 1.146, 0.558, 1.43, 0.686, 0.178, 1.024]]
result = src.reduce((r,a) => (a.forEach((n,j) => r[j] = (r[j]||0)+n), r),[])
console.log(result)
.as-console-wrapper{min-height:100%;}
Using for each for outer and inner array
let arr1 =[ [1, 2, 4, 3.6, 1.05, 4.65, 1.95, 0.5, 2.5],
[0.432, 0.602, 1.29, 1.146, 0.558, 1.43, 0.686, 0.178, 1.024]]
let arr2=[];arr1.forEach( (arr)=> arr.forEach((innerArr,index)=>{
if(!arr2[index])arr2[index]=0;arr2[index]=arr2[index]+innerArr;
}));
console.log(arr2);
Use the first array for mapping, add to each value the corresponding values from the other 3 arrays. You can create a function for it for arrays of arbitrary length (see sumArrays in the snippet)
const arrays = getData();
let sums = arrays[0].map( (v, i) => v + arrays[1][i] + arrays[2][i] + arrays[3][i] );
let sums2 = sumArrays(arrays);
console.log(sums);
console.log(sums2);
function sumArrays(arrays) {
const checkLengthEquality = () => {
let cando = arrays.map(v => v.length);
return Math.max.apply(null, cando) === Math.min.apply(null, cando);
};
if (!checkLengthEquality()) {
throw Error("Arrays not of equal length");
}
const sum = (v, i) => {
let len = arrays.length;
while(len-- > 1) {
v += arrays[len][i];
}
return v;
};
return arrays[0].map( (v, i) => sum(v, i) );
}
function getData() {
return [
[1, 2, 4, 3.6, 1.05, 4.65, 1.95, 0.5, 2.5],
[0.432, 0.602, 1.29, 1.146, 0.558, 1.43, 0.686, 0.178, 1.024],
[3.1, 2, 4.3, 3.8, 1.5, 6.5, 95, 1.5, 2.5],
[12, 1, 1.3, 8, 5.3, 6.2, 5, 1, 2.3]
];
}
.as-console-wrapper { top: 0; max-height: 100% !important; }
Related
Given the array const vals = [1, 2, 3, 4, 5, 6, 7, 8, 9];
How can I filter and return a new array of indexed key/value pair objects for example:
const vals = [1, 2, 3, 4, 5, 6, 7, 8, 9];
// My fail attempt using filter()
let obj = vals.filter((n, i) => {
return new Object({ i: n % 2 });
});
return obj;
// expected result [{1:2}, {3:4}, {5:6}, {7:8}]
I need to keep the index values as I will filter 2 different arrays with different criteria and associated them later.
Update
Second attempt using map() as suggested in the comments
let obj = vals.map((n, i) => {
if (n % 2) {
return { [i]: n };
}
});
Gives me the following:
[{0:1}, undefined, {2:3}, undefined, {4:5}, undefined, {6:7}, undefined, {8:9}]
To get a list of { key: value } objects where key is the index, and the values are only even without the odd values, you can do this:
const vals = [1, 2, 3, 4, 5, 6, 7, 8, 9];
const result = vals.map((v, i) => [i, v])
.filter(([_, v]) => v % 2 == 0)
.map(([i, v]) => ({ [i]: v }));
console.log(result);
With the first map, you make a list of [[0, 1], ...] pairs to save the index for later.
Then you filter your index-value pairs so only even values remain.
Then you pack those pairs into an object in another map.
This can be done more efficiently with a single iteration using reduce:
const vals = [1, 2, 3, 4, 5, 6, 7, 8, 9];
const result = vals.reduce((a, v, i) => {
if (v % 2 == 0) {
a.push({ [i]: v });
}
return a;
}, []);
console.log(result);
Youn can try simple for loop or the reduce function
let arr = [];
for(let i = 0; i<vals.length-1;i += 2)
{
let obj={};
obj[vals[i]]=vals[i+1];
arr.push(obj);
};
I have this array of numbers that i am working with that currently look this;
count = [1,4,3,1,2,3,4,5,6,2,3,5,7];
How can i transform and sort it to make it look like this;
count = [1,2,3,4,5,6,7,1,2,3,3,4,5];
Please help, any idea out there on how to approach this?
1) Get unique elements and sort
2) Get remaining elements and sort
3) combine (1) and (2) arrays.
count = [1, 4, 3, 1, 2, 3, 4, 5, 6, 2, 3, 5, 7];
const spSort = arr => {
const uniq = [...new Set([...arr])];
const rem = [];
const temp_set = new Set([...arr]);
arr.forEach(x => {
if (temp_set.has(x)) {
temp_set.delete(x);
} else {
rem.push(x);
}
});
return [...uniq.sort(), ...rem.sort()];
};
console.log(spSort(count));
Use a Set to create unique numbers and a hash object to keep count of duplicates:
const count = [1, 4, 3, 1, 2, 3, 4, 5, 6, 2, 3, 5, 7];
const hash = count.reduce((obj, num) => {
obj[num] = obj[num] ? ++obj[num] : 1;
return obj;
}, {});
const uniq = [...new Set(count)].sort();
uniq.forEach((num, _, arr) => {
while (--hash[num]) arr.push(num);
});
console.info(uniq);
Trying to solve this challenge on codewars. According to the challenge, the parts of array:
ls = [0, 1, 3, 6, 10]
Are
ls = [0, 1, 3, 6, 10]
ls = [1, 3, 6, 10]
ls = [3, 6, 10]
ls = [6, 10]
ls = [10]
ls = []
And we need to return an array with the sums of those parts.
So my code is as follows:
function partsSums(ls) {
let arrayOfSums = [];
while(ls.length > 0) {
let sum = ls.reduce((a, b) => a + b);
arrayOfSums.push(sum);
ls.shift();
}
return arrayOfSums;
}
console.log(partsSums([0, 1, 3, 6, 10]));
The issue is that it wants us to add the last sum 0 when the array is empty. So we should be getting:
[ 20, 20, 19, 16, 10, 0 ]
Instead of
[ 20, 20, 19, 16, 10]
So I tried this:
function partsSums(ls) {
let arrayOfSums = [];
while(ls.length > 0) {
let sum = ls.reduce((a, b) => a + b);
arrayOfSums.push(sum);
ls.shift();
}
arrayOfSums.push(0);
return arrayOfSums;
}
console.log(partsSums([0, 1, 3, 6, 10]));
And this:
function partsSums(ls) {
ls.push(0);
let arrayOfSums = [];
while(ls.length > 0) {
let sum = ls.reduce((a, b) => a + b);
arrayOfSums.push(sum);
ls.shift();
}
return arrayOfSums;
}
But these caused execution time-out errors on Codewars:
Execution Timed Out (12000 ms)
So I also tried:
function partsSums(ls) {
let arrayOfSums = [];
while(ls.length > -1) {
let sum = ls.reduce((a, b) => a + b);
arrayOfSums.push(sum);
ls.shift();
}
return arrayOfSums;
}
But now this causes a TypeError:
TypeError: Reduce of empty array with no initial value
I am not understanding the concept of how to get 0 into the array when all of the values have been shifted out. The challenge seems to want 0 as the final "sum" of the array, even when the array is empty. But you cannot reduce an empty array - what else can I do here?
EDIT: Tried adding initial value to the reduce method:
function partsSums(ls) {
let arrayOfSums = [];
while(ls.length > 0) {
let sum = ls.reduce((a, b) => a + b, 0);
arrayOfSums.push(sum);
ls.shift();
}
return arrayOfSums;
}
Unfortunately this still fails the basic test :
expected [] to deeply equal [ 0 ]
There is no reason to compute the sum over and over. On a long array this will be very inefficient ( O(n²) ) and might explain your timeout errors. Compute the sum at the beginning and then subtract each element from it in a loop.
ls = [0, 1, 3, 6, 10]
function partsSums(ls) {
let sum = ls.reduce((sum, n) => sum + n, 0)
res = [sum]
for (let i = 1; i <= ls.length; i++){
sum -= ls[i-1]
res.push(sum )
}
return res
}
console.log(partsSums(ls))
Another solution that passed all of the tests:
function partsSums(ls) {
let result = [0],
l = ls.length - 1;
for (let i = l; i >= 0; i--) {
result.push(ls[i] + result[ l - i]);
}
return result.reverse();
}
console.log(partsSums([]));
console.log(partsSums([0, 1, 3, 6, 10]));
console.log(partsSums([1, 2, 3, 4, 5, 6]));
console.log(partsSums([744125, 935, 407, 454, 430, 90, 144, 6710213, 889, 810, 2579358]));
You could use for loop with slice and when i == 0 you can slice len + 1 which is going to return you empty array and sum will be 0.
function partsSums(arr) {
const res = [], len = arr.length
for (let i = len; i > -1; i--) {
res.push(arr.slice(-i || len + 1).reduce((a, n) => a + n, 0))
}
return res;
}
console.log(partsSums([0, 1, 3, 6, 10]));
console.log(partsSums([1, 2, 3, 4, 5, 6]));
console.log(partsSums([744125, 935, 407, 454, 430, 90, 144, 6710213, 889, 810, 2579358]));
You can also use two double reduce and if there is no next element push zero.
function partsSums(arr) {
const sum = arr => arr.reduce((r, e) => r + e, 0);
return arr.reduce((r, e, i, a) => {
const res = sum(a.slice(i, a.length));
return r.concat(!a[i + 1] ? [res, 0] : res)
}, [])
}
console.log(partsSums([0, 1, 3, 6, 10]));
console.log(partsSums([1, 2, 3, 4, 5, 6]));
console.log(partsSums([744125, 935, 407, 454, 430, 90, 144, 6710213, 889, 810, 2579358]));
try this with recursion :
function partsSums(ls) {
let sum = ls.reduce((a, b) => a + b, 0);
return ls.length > 0 ? [sum].concat(partsSums(ls.slice(1))) : [0];
}
console.log(partsSums([0, 1, 3, 6, 10]));
console.log(partsSums([1, 2, 3, 4, 5, 6]));
console.log(partsSums([744125, 935, 407, 454, 430, 90, 144, 6710213, 889, 810, 2579358]));
Here's one thing you could do
function partsSums(ls) {
if(!ls.length) return [0];
let prevTotal = ls.reduce((a,b) => a + b);
return [prevTotal, ...ls.map(val => prevTotal -= val)]
}
console.log(partsSums([0, 1, 3, 6, 10]));
You could iterate from the end and take this value plus the last inserted value of the result set.
This approach works with a single loop and without calculating the maximum sum in advance.
function partsSums(ls) {
var result = [0],
i = ls.length;
while (i--) {
result.unshift(ls[i] + result[0]);
}
return result;
}
console.log(partsSums([0, 1, 3, 6, 10]));
console.log(partsSums([]));
.as-console-wrapper { max-height: 100% !important; top: 0; }
With push and reverse.
function partsSums(ls) {
var result = [0],
l = 0,
i = ls.length;
while (i--) result.push(l += ls[i]);
return result.reverse();
}
console.log(partsSums([0, 1, 3, 6, 10]));
console.log(partsSums([]));
.as-console-wrapper { max-height: 100% !important; top: 0; }
I have an array like so
const arr = [3,6,9,12,18,21,24,27,33,36];
I want the array arr split into chunks at 12, 21 and 33. That is at the index 3, 5, and 8. I want to produce another array chunks looking like this..
const chunks = [[3,6,9,12],[18,21],[24,27,33],[36]];
The solutions I have seen here basically split arrays into 'n' chunks. Basically I want to split at arrays at several (specified) indexes.
I do not mind an underscore.js/lodash solution. Thanks
You could use reduceRight and decide which elements to split at. Since you’re providing the last values of a sub-array rather than the first ones, going from right to left is actually a bit easier, hence I use a reduceRight rather than a reduce.
Split by value
const arr = [3, 6, 9, 12, 18, 21, 24, 27, 33, 36],
splitValues = [12, 21, 33],
chunks = arr.reduceRight((result, value) => {
result[0] = result[0] || [];
if (splitValues.includes(value)) {
result.unshift([value]);
} else {
result[0].unshift(value);
}
return result;
}, []);
console.log(chunks);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Split by index
const arr = [3, 6, 9, 12, 18, 21, 24, 27, 33, 36],
splitIndexes = [3, 5, 8],
chunks = arr.reduceRight((result, value, index) => {
result[0] = result[0] || [];
if (splitIndexes.includes(index)) {
result.unshift([value]);
} else {
result[0].unshift(value);
}
return result;
}, []);
console.log(chunks);
.as-console-wrapper { max-height: 100% !important; top: 0; }
const arr = [3,6,9,12,18,21,24,27,33,36];
// Important: this array gets mutated. Make a copy if that's not okay.
const inds = [3,5,8];
const chunked = arr.reduce((p, c, i) => { if (i-1 === inds[0]) { inds.shift(); p.push([]); } p[p.length-1].push(c); return p; }, [[]]);
console.log(chunked)
Here's an alternative way of doing it that I think is a bit clearer.
function chunkIt(arr, indexes) {
const ret = [];
let last = 0;
indexes.forEach(i => {
ret.push(arr.slice(last, i + 1));
last = i + 1;
});
if (last < arr.length) {
ret.push(arr.slice(last));
}
return ret;
}
console.log(chunkIt([3,6,9,12,18,21,24,27,33,36], [3,5,8]));
A bit "simplified" version with the reversed indexes, but splice modifies the source array:
arr = [3, 6, 9, 12, 18, 21, 24, 27, 33, 36]
chunks = [9, 6, 4, 0].map(i => arr.splice(i)).reverse()
console.log(JSON.stringify(chunks))
or slice can be used instead to preserve the source array:
arr = [3, 6, 9, 12, 18, 21, 24, 27, 33, 36], indexes = [0, 4, 6, 9]
chunks = indexes.map((e, i) => arr.slice(e, indexes[i + 1]))
console.log(JSON.stringify(chunks))
i have two array, lets say
priceArray= [1,5,3,7]
userIdArray=[11, 52, 41, 5]
i need to sort the priceArray, so that the userIdArray will be also sorted.
for example the output should be:
priceArray= [1,3,5,7]
userIdArray=[11, 41, 52, 5]
any ideas how to do it?
i am writing my server in NodeJS
Taken from Sorting with map and adapted for the userIdArray:
// the array to be sorted
var priceArray = [1, 5, 3, 7],
userIdArray = [11, 52, 41, 5];
// temporary array holds objects with position and sort-value
var mapped = priceArray.map(function (el, i) {
return { index: i, value: el };
});
// sorting the mapped array containing the reduced values
mapped.sort(function (a, b) {
return a.value - b.value;
});
// container for the resulting order
var resultPrice = mapped.map(function (el) {
return priceArray[el.index];
});
var resultUser = mapped.map(function (el) {
return userIdArray[el.index];
});
document.write('<pre>' + JSON.stringify(resultPrice, 0, 4) + '</pre>');
document.write('<pre>' + JSON.stringify(resultUser, 0, 4) + '</pre>');
With proper data structure, as rrowland suggest, you might use this:
var data = [{
userId: 11, price: 1
}, {
userId: 52, price: 15
}, {
userId: 41, price: 13
}, {
userId: 5, price: 17
}];
data.sort(function (a, b) {
return a.price - b.price;
});
document.write('<pre>' + JSON.stringify(data, 0, 4) + '</pre>');
A bit shorter with ES6
var priceArray = [1, 5, 3, 7],
userIdArray = [11, 52, 41, 5],
temp = Array.from(priceArray.keys()).sort((a, b) => priceArray[a] - priceArray[b]);
priceArray = temp.map(i => priceArray[i]);
userIdArray = temp.map(i => userIdArray[i]);
console.log(priceArray);
console.log(userIdArray);
.as-console-wrapper { max-height: 100% !important; top: 0; }
It's hard to prescribe a better solution without knowing the whole use-case. That said, if you need these sorted by ID, it may make more sense to create a single array that contains user objects:
var users = [
{ id: 123, price: 25.00 },
{ id: 124, price: 50.00 }
];
users.sort(function(a, b) {
return a.id - b.id;
});
Or, if they don't need to be sorted, you can simply create a map of users by id:
var userPrices = {
123: 25.00,
124: 50.00
};
Building on Rrowland's answer, you can create the array of objects with a library like lodash:
var prices = [1, 5, 8, 2];
var userIds = [3, 5, 1, 9];
var pairs = _.zipWith(prices, userIds, function(p, u) {
return { price: p, userId: u };
});
This will give you an object like:
[
{ price: 1, userId: 3 },
{ price: 5, userId: 5 },
... etc
]
Then, for sorting, you can simply use a Javascript sort:
pairs.sort(function(p) { return p.price });
If you really need it as an array of userIds, you can get it back, after the sort:
var sortedUserId = pairs.map( function(p) { return p.userId });
// returns [ 3, 9, 5, 8 ];
I have seen a nice talk about making impossible state impossible. This covered the 2 arrays that are related but can go out of sync and better to use one array of objects that have 2 properties (as mentioned several times).
However; if you want to mutate both arrays and sort them the same way you can do the following:
//this will mutate both arrays passed into it
// you could return the arrays but then you need to do arr.slice(0).sort(...) instead
const sortSame = sortFn => (arrayToSort,arrayToSortSame) => {
const sortResults = [];
arrayToSort.sort(//will mutate the array
(a,b)=>{
const result = sortFn(a,b);
sortResults.push(result);
return result
}
);
arrayToSortSame.sort(()=>sortResults.shift());
return undefined;
}
const priceArray= [1,5,3,7];
const userIdArray=[11, 52, 41, 5];
const numSortSameAscending = sortSame((a,b)=>a-b);
numSortSameAscending(priceArray,userIdArray);
console.log(
priceArray,userIdArray
)
Even though the code in this answer may look simpler it is not the cheapest way to do it, as mapping is a cheaper operation than sorting (better to map 3 times and sort once then to sort twice) depending on the size of the arrays and how much the original array is out of order this way of sorting same may be very expensive.