I have two separate arrays and I'm trying to create a new nested array that has values grouped together.
Can I use the map() method and pair each item inside the map method?
There is a similar question here: Map an array of arrays
However, he context is different because I don't have a nested array to begin with.
var letters = [a, b, c];
var numbers = [1, 2, 3];
var lettersAndNumbers = letters.map((letter) => {
numbers.forEach((number) => {
return letter, number;
);
});
// lettersAndNumbers = [[a, 1], [b, 2], [c, 3]]
Thank you for any tips, hints, or solutions!
To do this, use the following
var letters = ['a','b','c'];
var numbers = [1, 2, 3];
var letterAndNumbers = letters.map((letter,index) => {
return [letter,numbers[index]];
})
And if you print it, you will receive the following output
console.log(letterAndNumbers)
[ [ 'a', 1 ], [ 'b', 2 ], [ 'c', 3 ] ]
The second parameter of .map() is Index. Make use of it for retrieve a numbers[i] by that iterating index:
const letters = ["a", "b", "c"];
const numbers = [1, 2, 3];
const lettersAndNumbers = letters.map((a, i) => [a, numbers[i]]);
console.log(lettersAndNumbers)
// lettersAndNumbers = [[a, 1], [b, 2], [c, 3]]
I would use a map but here is a reduce just for the sake of it.
var letters = ['a', 'b', 'c'];
var numbers = [1, 2, 3];
var lettersAndNumbers = (letters, numbers) => letters.reduce((results, letter, index) => {
results.push([letter, numbers[index]]);
return results;
}, []);
console.log(lettersAndNumbers(letters, numbers));
Related
I have 2 arrays:
var a = [1, 2, 3]
var b = [a, b, c]
What I want to get as a result is:
[[1, a], [2, b], [3, c]]
It seems simple but I just can't figure out.
I want the result to be one array with each of the elements from the two arrays zipped together.
Use the map method:
var a = [1, 2, 3]
var b = ['a', 'b', 'c']
var c = a.map(function(e, i) {
return [e, b[i]];
});
console.log(c)
DEMO
Zip Arrays of same length:
Using Array.prototype.map()
const zip = (a, b) => a.map((k, i) => [k, b[i]]);
console.log(zip([1,2,3], ["a","b","c"]));
// [[1, "a"], [2, "b"], [3, "c"]]
Zip Arrays of different length:
Using Array.from()
const zip = (a, b) => Array.from(Array(Math.max(b.length, a.length)), (_, i) => [a[i], b[i]]);
console.log( zip([1,2,3], ["a","b","c","d"]) );
// [[1, "a"], [2, "b"], [3, "c"], [undefined, "d"]]
Using Array.prototype.fill() and Array.prototype.map()
const zip = (a, b) => Array(Math.max(b.length, a.length)).fill().map((_,i) => [a[i], b[i]]);
console.log(zip([1,2,3], ["a","b","c","d"]));
// [[1, "a"], [2, "b"], [3, "c"], [undefined, "d"]]
Zip Multiple (n) Arrays:
const zip = (...arr) => Array(Math.max(...arr.map(a => a.length))).fill().map((_,i) => arr.map(a => a[i]));
console.log(zip([1,2], [3,4], [5,6])); // [[1,3,5], [2,4,6]]
Zipping by leveraging generator functions
You can also use a generator function to zip().
const a = [1, 2, 3]
const b = ['a', 'b', 'c']
/**
* Zips any number of arrays. It will always zip() the largest array returning undefined for shorter arrays.
* #param {...Array<any>} arrays
*/
function* zip(...arrays){
const maxLength = arrays.reduce((max, curIterable) => curIterable.length > max ? curIterable.length: max, 0);
for (let i = 0; i < maxLength; i++) {
yield arrays.map(array => array[i]);
}
}
// put zipped result in an array
const result = [...zip(a, b)]
// or lazy generate the values
for (const [valA, valB] of zip(a, b)) {
console.log(`${valA}: ${valB}`);
}
.as-console-wrapper { max-height: 100% !important; top: 0; }
The above works for any number of arrays and will zip() the longest array so undefined is returned as a value for shorter arrays.
Zipping of all Iterables
Here a function which can be used for all Iterables (e.g. Maps, Sets or your custom Iterable), not just arrays.
const a = [1, 2, 3];
const b = ["a", "b", "c"];
/**
* Zips any number of iterables. It will always zip() the largest Iterable returning undefined for shorter arrays.
* #param {...Iterable<any>} iterables
*/
function* zip(...iterables) {
// get the iterator of for each iterables
const iters = [...iterables].map((iterable) => iterable[Symbol.iterator]());
let next = iters.map((iter) => iter.next().value);
// as long as any of the iterables returns something, yield a value (zip longest)
while(anyOf(next)) {
yield next;
next = iters.map((iter) => iter.next().value);
}
function anyOf(arr){
return arr.some(v => v !== undefined);
}
}
// put zipped result in aa array
const result = [...zip(a, new Set(b))];
// or lazy generate the values
for (const [valA, valB] of zip(a, new Set(b))) {
console.log(`${valA}: ${valB}`);
}
Obviously it would also be possible to just use [...Iterable] to transform any Iterable to an array and then use the first function.
Using the reduce method:
const a = [1, 2, 3]
const b = ['a', 'b', 'c']
var c = a.reduce((acc, curr, ind) => {
acc.push([curr, b[ind]]);
return acc;
}, []);
console.log(c)
With forEach method:
const a = [1, 2, 3]
const b = ['a', 'b', 'c']
const c = [];
a.forEach((el, ind) => {
c.push([el, b[ind]])
});
console.log(c)
Providing a solution with imperative programming by a simple for loop.
This performs better when doing the zip operation on huge data sets compared to the convenient array functions like map() and forEach().
Example:
const a = [1, 2, 3];
const b = ['a', 'b', 'c'];
const result = [];
for (let i = 0; i < a.length; i++) {
result.push([a[i], b[i]]);
}
console.log(result);
And if you want a 1 line simpler solution then you can use a library like ramda which has a zip function.
Example:
const a = [1, 2, 3];
const b = ['a', 'b', 'c'];
const result = R.zip(a, b);
console.log(result);
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)
Note: Not a duplicate problem.. here I need to skip empty arrays.
Say I have several arrays like:
var a = [1, 2, 3, 4],
b = [2, 4],
c = [],
d = [4];
Using following function, I could get the desired result: [4]
var a = [1, 2, 3, 4],
b = [2, 4],
c = [],
d = [4];
var res = [a, b, c, d].reduce((previous, current) =>
!previous.length || previous.filter((x) => !current.length || current.includes(x)),
);
console.log(res)
I included !current.length || above to bypass empty array c. But this doesn't work if first array in the collection i.e. a is empty. The result would be [].
This code will work as you expected (vanilla JS, support old browsers):
var a = [1, 2, 3, 4],
b = [2, 4],
c = [],
d = [4];
var res = [a, b, c, d].reduce(function(acc, arr) {
// ignore empty array
if(arr.length == 0) return acc;
// assign first non-empty array to accumudation
if(acc.length == 0) return arr;
// otherwise, accumudation will be insection of current accomudation and current array
return acc.filter(function(n) {
return arr.indexOf(n) !== -1;
});
}, []);
console.log(res)
Just filter. Makes the code much more readable
var a = [1, 2, 3, 4],
b = [2, 4],
c = [],
d = [4];
var res = [c, b, a, d].filter(arr => arr.length).reduce((previous, current) =>
previous.filter((x) => current.includes(x)),
);
console.log(res)
I have an array that has other arrays in it which have been pushed in. For an example:
const Arrays = [ [1,2,3], [4,5,6], [7,8,9], [2,1,3] ];
let myArr = [];
Arrays.map(arr => {
if(myArr.indexOf(arr)){
return
}
myArr.push(arr)
})
const myArr = [ [1,2,3], [4,5,6], [7,8,9], [2,1,3] ];
In this array you can see that there are two arrays with the same set of numbers 1, 2 and 3. I want to somehow set a condition saying:
If this array already exist then do not add this array in any order again to prevent this from happening. So that when it comes in the loop that this set of numbers comes up again it will just skip over it.
You can use some() and every() methods to check if same array already exists before push().
const myArr = [ [1,2,3], [4,5,6], [7,8,9] ];
let input = [2,1,3]
function check(oldArr, newArr) {
return oldArr.some(a => {
return a.length == newArr.length &&
a.every(e => newArr.includes(e))
})
}
if(!check(myArr, input)) myArr.push(input)
console.log(myArr)
You can make temp array with sorted element with joined and check by indexOf
const myArr = [ [1,2,3], [4,5,6], [7,8,9], [2,1,3],[6,5,4] ];
var newArr = [];
var temp = [];
for(let i in myArr){
let t = myArr[i].sort().join(",");
if(temp.indexOf(t) == -1){
temp.push(t);
newArr.push(myArr[i]);
}
}
console.log(newArr);
The accepted answer does not respect the special case where only two values are in the array and the array has to check against two values in a different count like
[1, 1, 2]
and
[1, 2, 2]
which are different arrays.
For a working solution, I suggest to use a Map and count the occurences of same values of the first array and subtract the count of the values for the other arrray.
As result return the check if all elements of the Map are zero.
function compare(a, b) {
var map = new Map;
a.forEach(v => map.set(v, (map.get(v) || 0) + 1));
b.forEach(v => map.set(v, (map.get(v) || 0) - 1));
return [...map.values()].every(v => !v);
}
var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [2, 1, 3], [1, 1, 2], [1, 2, 2], [2, 1, 1], [2, 1, 2]],
unique = array.reduce((r, a) => (r.some(b => compare(a, b)) || r.push(a), r), []);
console.log(unique);
.as-console-wrapper { max-height: 100% !important; top: 0; }
One way is to sort them numerically with .sort() then compare them.
I want to combine two arrays into one Object with name "data"
Didn't find any efficient way
arrays:
var N =[ 1, 2, 3];
var s =[ a, b, c];
combine them into object:
var data= { s:[ a, b, c], N: [ 1, 2, 3 ] };
The easiest way would be:
const N = [1, 2, 3];
const s = ['a', 'b', 'c'];
const data = { s, N };
This is equivalent to:
const N =[ 1, 2, 3];
const s = ['a', 'b', 'c'];
const data = { s: s, N: N };
Note: I used const since the variables aren't reassigned.
Do it this way:
var N =[ 1, 2, 3];
var s =[ a, b, c];
var obj = {N, s};
var N =[ 1, 2, 3];
var s =[ 'a', 'b', 'c'];
var data = {s, N};
console.log(data);
Just pass your arrays (N and s) as variables to your new object.
You can do this in few ways:
let myObject = { N: N, s: s }
If you do this way you can type any other key. For example:
let myObject = { firstArray: N, secondArray: s }
and now you can access to N and s arrays as myObject.firstArray etc
Use short notation:
let myObject = { N, s }
This code will look up for variables N and s and write it inside your new object, which will give the same result as let myObject = { N: N, s: s }