Working to get a better grasp of nested arrays. I have an array with two arrays nested inside as the indices. I am trying to figure out how to add these. I understand how you would add them if they were separate arrays, but I am wondering how/if possible you can map through a nested array to add the indices.
The current array that I am looking at is
strArr= [[5, 2, 3], [2, 2, 3] ];
If this was two separate arrays I could simply run a map with index as a second parameter such as ...
var arr = [1,2,3,4];
var arr2 = [1,1,1,2,9];
arr.map((a, i) => a + arr2[i]);
However, I am not able to achieve this with the index
strArr.map((a,idx) => a[0][idx] + a[1][idx]) // [Nan, Nan]
The best I can do to get any addition is
return strArr.map(a => a[0] + a[1]) // [7,4]
However, I am not sure why I am only getting [7,4]
You iterate over the outer array, which has a length of 2. Therefore you get a result of two elements.
You could use Array#reduce for the outer array and Array#forEach for the inner arrays and sum the values at a given index.
var strArr= [[5, 2, 3], [2, 2, 3] ];
console.log(strArr.reduce((r, a) => (a.forEach((b, i) => r[i] = (r[i] || 0) + b), r), []));
You can use the .reduce function to sum your indices
var arr = [1, 2, 3, 4];
var arr2 = [1, 1, 1, 2];
var result = arr
.map((item, i) => i + arr2[i])
.reduce((memo, value) => memo + value);
console.debug("res: ", result);
// res: 11
However you will have to handle cases when the array lengths are not equal to eachover or not numerical values
Map each element in the parent array (sub-arrays)
For each sub-array reduce and sum
strArr= [[5, 2, 3], [2, 2, 3] ];
var result = strArr.map((arr)=>arr.reduce((a,b)=>a+b));
console.log(result);
Why not just target/split the original array?
"If this was two separate arrays I could simply run a map with index as a second parameter"
Then make it two separate arrays...
strArr= [[5, 2, 3], [2, 2, 3] ]; /* becomes strArr[0] & strArr[1] */
console.log(strArr[0].map((a, i) => a + strArr[1][i]));
Related
I have 3 arrays. For example, given the arrays are
arr1 = [2, 7]
arr2 = [0, 1, 16]
arr3 = [3, 6, 9]
And I would like to rearrange them according to the numbers and output as an array.
result = ['arr2', 'arr2', 'arr1', 'arr3', 'arr3', 'arr1', 'arr3', 'arr2']
I think it might have something to do with looping, but I've no luck after struggling for a while. Is there any way to get the expected result?
You could move the values to an object and take another object for the indices and sort an array of key.
Then take the key at index zero and go on until the index is equal to the length of the array, then stop the iteration.
const
arr1 = [2, 7],
arr2 = [0, 1, 16],
arr3 = [3, 6, 9],
values = { arr1, arr2, arr3 },
result = [],
keys = Object.keys(values),
indices = Object.fromEntries(keys.map(k => [k, 0]));
while (true) {
keys.sort((a, b) => (values[a][indices[a]] ?? Number.MAX_VALUE) - (values[b][indices[b]] ?? Number.MAX_VALUE));
if (indices[keys[0]] === values[keys[0]].length) break;
result.push(keys[0]);
indices[keys[0]]++;
}
console.log(...result);
A shorter approach by mapping entries, sorting and mapping again.
const
arr1 = [2, 7],
arr2 = [0, 1, 16],
arr3 = [3, 6, 9],
result = Object
.entries({ arr1, arr2, arr3 })
.flatMap(([k, a]) => a.map(v => [k, v]))
.sort(([, a], [, b]) => a - b)
.map(([k]) => k);
console.log(...result);
Option 1. Allocate an array whose size is equal to the total count of elements in the 3 arrays. Populate the newly created array with the elements from your 3 small arrays. Then sort the created array.
Option 2. Merge 2 of the 3 arrays to produce a sorted array with elements from the chosen 2 small arrays. Then merged the sorted array from the previous step with the 3rd array to get the array that you need.
Not an elegant solution but maybe something like can help
arr1 = [2, 7]
arr2 = [0, 1, 16]
arr3 = [3, 6, 9]
let concatedArray = [...arr1, ...arr2, ...arr3].sort((a, b) => a - b);
let finalArr = []
concatedArray.forEach(val => {
let doesNumberExist = false;
let arrName = ''
doesNumberExist = arr1.includes(val);
arrName = 'arr1';
if (!doesNumberExist) {
doesNumberExist = arr2.includes(val);
arrName = 'arr2'
}
if (!doesNumberExist) {
doesNumberExist = arr3.includes(val);
arrName = 'arr3'
}
finalArr.push(arrName);
}
)
console.log(finalArr)
This question already has answers here:
How to remove duplicates from a two-dimensional array? [closed]
(3 answers)
Closed 3 years ago.
I have an array like this:
let x = [[1, 2], [3, 4], [1, 2], [2, 1]];
What should I do to retrieve an array without the duplicates?
[[1, 2], [3, 4], [2, 1]];
I would like to use the filter method. I tried this but it doesn't work:
x.filter((value,index,self) => (self.indexOf(value) === index))
EDIT: as I specified to use the filter method, I don't think this question is a duplicate. Also, I got several interesting answers.
Try converting the inner arrays to a string, then filter the dupes and parse the string again.
let x = [[1, 2], [3, 4], [1, 2]];
var unique = x.map(ar=>JSON.stringify(ar))
.filter((itm, idx, arr) => arr.indexOf(itm) === idx)
.map(str=>JSON.parse(str));
console.log(unique);
Filter just causes things to get into O(n^2).
The currently accepted answer uses .filter((itm, idx, arr) => arr.indexOf(itm) === idx) which will cause the array to be iterated each time during each iteration... n^2.
Why even go there? Not only that, you need to parse in the end. It is a lot of excess.
There is no real good way to use filter without hitting O(n^2) here, so if performance is the goal is should probably be avoided.
Instead, just use reduce. It is very straightforward and fast easily accomplishing O(n).
"Bin reduce the set to unique values."
let x = [[1, 2], [3, 4], [1, 2], [2, 1]];
let y = Object.values(x.reduce((p,c) => (p[JSON.stringify(c)] = c,p),{}));
console.log(y);
In case it isn't as clear, here is a more readable version of the bin reduction.
// Sample Data
let dataset = [[1, 2], [3, 4], [1, 2], [2, 1]];
// Create a set of bins by iterating the dataset, which
// is an array of arrays, and structure the bins as
// key: stringified version of the array
// value: actual array
let bins = {};
// Iteration
for(let index = 0; index < dataset.length; index++){
// The current array, from the array of arrays
let currentArray = dataset[index];
// The JSON stringified version of the current array
let stringified = JSON.stringify(currentArray);
// Use the stringified version of the array as the key in the bin,
// and set that key's value as the current array
bins[stringified] = currentArray;
}
// Since the bin keys will be unique, so will their associated values.
// Discard the stringified keys, and only take the set of arrays to
// get the resulting unique set.
let results = Object.values(bins);
console.log(results);
If you were to have to go the route of filter, then n^2 must be used. You can iterate each item looking for existence using every.
"Keep every element which does not have a previous duplicate."
let x = [
[1, 2],
[3, 4],
[1, 2],
[2, 1]
];
let y = x.filter((lx, li) =>
x.every((rx, ri) =>
rx == lx ||
(JSON.stringify(lx) != JSON.stringify(rx) || li < ri))
);
console.log(y);
Okay, the string hash idea is brilliant. Props to I wrestled a bear once. I think the code itself could be a bit better though, so here's how I tend to do this type of thing:
let x = [[1, 2], [3, 4], [1, 2]];
const map = new Map();
x.forEach((item) => map.set(item.join(), item));
console.log(Array.from(map.values()));
And if you want an ugly one liner:
let x = [[1, 2], [3, 4], [1, 2]];
const noRepeats = Array.from((new Map(x.map((item) => [item.join(), item]))).values());
console.log(noRepeats);
This is a solution with time complexity of O(n) where n is the number of elements in your array.
Using the filter method as the OP wants it:
const x = [[1, 2], [3, 4], [1, 2], [2, 1]];
const s = new Set();
const res = x.filter(el => {
if(!s.has(el.join(""))) {
s.add(el.join(""));
return true;
}
return false
})
console.log(res)
My personal preference here is to use ForEach as it looks more readable.
const x = [[1, 2], [3, 4], [1, 2], [2, 1]];
const s = new Set();
const res = [];
x.forEach(el => {
if(!s.has(el.join(""))) {
s.add(el.join(""));
res.push(el)
}
})
console.log(res);
We are using a Set and a simple combination of the elements of the array to make sure they are unique. Otherwise this would become O(n^2).
The equivalent to
x.filter((value,index,self) => (self.indexOf(value) === index))
would be
x.filter((v,i,self) => {
for1:
for (let j = 0; j < self.length; j++) {
if (i == j) {
return true;
}
if (self[j].length != v.length) {
continue;
}
for (let k = 0; k < v.length; k++) {
if (self[j][k] != v[k]) {
continue for1;
}
}
return false;
}
return true;
})
Unlike some of the other answers, this does not require a conversion to string and can thus work with more complex values.
Use === instead of == if you want.
The time complexity is not great, of course.
indexOf does not work on identical instances of arrays/objects type elements within an array, as such arrays just hold references.
In filter function instance you get via parameter v (in below code) is not the same instance as stored in array, making indexOf unable to return the index of it.
In below code, by converting objects to strings we can use indexOf to find duplicates.
let x = [[1, 2], [3, 4], [1, 2], [2, 1]];
console.log(x.
map(function(v){
return JSON.stringify(v)
})
.filter(function(v, i, o) {
return o.length == i ? true : o.slice(i + 1).indexOf(v) == -1;
})
.map(function(v) {
return JSON.parse(v)
})
);
Array of arrays:
list = [[1, 2, 3], [4, 5, 6]];
I want to reduce (combine) each inner array (1+2+3) and (4+5+6) and then put those results 6 and 15 in their own array like [6, 15].
I have below code:
list.reduce((a, b) => a + b);
but it's just strangely combining everything in all the arrays.
You need to iterate both the outer and the inner arrays.
list.map(array => array.reduce((a, b) => a + b))
Use .map() with .reduce():
let list = [[1, 2, 3], [4, 5, 6]];
let reducer = (a, b) => (a + b);
let result = list.map(arr => arr.reduce(reducer));
console.log(result);
You can do it like this
map() with map we iterate on every element of arr.
reduce() - with reduce we reduce each element to a single value.
let arr = [[1,2,3],[4,5,6]];
let op = arr.map(e => e.reduce( (a, b) => a + b, 0) );
console.log(op);
You can also achieve this with Array.from since its second parameter is Array.map function and inside you can do your Array.reduce for the summation:
const data = [[1, 2, 3], [4, 5, 6]]
const result = Array.from(data, x => x.reduce((r,c) => r+c))
console.log(result)
I'm having trouble finding a solution to a combinatronics problem while making a card game in javascript. I'd like to get all combinations of a set such that all elements are used.
given: [1, 2, 3]
returns: [
[[1], [2], [3]],
[[1, 2], 3],
[[1, 3], 2],
[[2, 3], 1],
[[1, 2, 3]]
]
the game is Cassino.
function permute(arr){
const res = [];
for(var map = 1; map < 2 ** arr.length; map++){
const rest = [],
subset = arr.filter((el, i) => (map & (1 << i)) || (rest.push(el), false));
//console.log(subset, rest);
res.push(...(rest.length ? permute(rest).map(arr => [subset,...arr]) : [[subset]]));
}
//console.log(res);
return res;
}
console.log(permute([1,2,3]))
Try it!
This problem can be solved in a recursive manner.
First we need to declare two arrays, one which will contains the input (the given array) and the other will contains the result (initially empty)
var givenArray = [1, 2, 3];
var resultArray = [];
Now let's create our recursive function that will push a subset array to our result array:
function getSubArray(array, position) {
if(position === givenArray.length) {
resultArray.push(array);
return;
}
getSubArray(array.concat(givenArray[position]), position+1);
getSubArray(array, position+1);
}
Now to start set all the subsets to the resultArray we just need to call our getSubArray function with an empty array and a start position which is 0 as arguments
getSubArray([], 0);
After that just remove the last element of the resultArray if you want to remove the empty set ([]) from the result
resultArray.splice(-1,1);
You can test the algorithm online via this link: https://jsbin.com/xigipihebe/edit?js,console
How do I change a JS array in place (like a Ruby "dangerous" method, e.g. with trailing !)
Example:
If I have this:
var arr = [1, 2, 3]
How can I make this:
arr === [2, 4, 6]
(assuming I have an appropriate function for doubling numbers) in one step, without making any more variables?
Use Array.prototype.forEach() , third parameter is this : input array
var arr = [1, 2, 3];
arr.forEach(function(el, index, array) {
array[index] = el * 2
});
console.log(arr)
A smart Array.prototype.map() and an assignment will do.
The map() method creates a new array with the results of calling a provided function on every element in this array.
var arr = [1, 2, 3];
arr = arr.map(function (a) {
return 2 * a;
});
document.write('<pre>' + JSON.stringify(arr, 0, 4) + '</pre>');
map() returns a new array, but it can also modify the array in-place if the callback function works on the array's elements:
function double(el, i, array) {
array[i]= el * 2;
} //double
var arr= [1, 2, 3];
arr.map(double);
console.log(arr); // [2, 4, 6]