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);
For example, if I have 2 arrays being:
let array1 = [1,2,3]; and let array2 = [5,6,7,8,9], how would I create a new 3rd array that only contains the elements from array2 that are at the extra indexes (so the new array would only contain [8,9] since they are at index 3 and 4).
Thanks!
You can use the Javascript slice() function
arr1 = [1,2,3]
arr2=[5,6,7,8,9]
arr3 = arr2.slice(arr1.length , arr2.length)
console.log(arr3)
There are plenty of ways to do that, here's a solution that uses slice method with a negative index. That negative index is (array2.length - array1.length) * -1.
const array1 = [1, 2, 3],
array2 = [5, 6, 7, 8, 9],
sliceArray = (a1, a2) => a2.length <= a1.length ? [] : a2.slice((a2.length - a1.length) * -1)
console.log(sliceArray([], [])); // returns: []
console.log(sliceArray([1, 3, 6], [1, 2])); // returns: []
console.log(sliceArray(array1, array2)); // returns: [8, 9]
let array1 = [1,2,3,8,9];
let array2 = [5,6,7];
let array3=array1.length > array2.length ?array1.slice(array2.length,array1.length):array2.slice(array1.length,array2.length)
console.log(array3);
Use ternary operator and slice method
You can use a function that will find the longer array and slice it for you. That way, you don't need to know in advance which array is longer:
function collectExtra (arrayA, arrayB) {
if (arrayA.length === arrayB.length) return [];
const [shorter, longer] = [arrayA, arrayB]
.sort((a, b) => a.length - b.length);
return longer.slice(shorter.length);
}
const array1 = [1,2,3];
const array2 = [5,6,7,8,9];
const result = collectExtra(array1, array2);
console.log(result); // [8, 9]
const result2 = collectExtra(array2, array1);
console.log(result2); // [8, 9]
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'm actually looking for a way to check if two values of an array or more are equal. Here are some examples :
[1, 2, 3] // false
[1, 1, 5] // true
['a', 'b', 'a', 'c'] // true
[10, 10, 10] // true
I found this function that gives 'true' if EVERY array values are equal, but that's not what i'd like :
[1,1,1,1].every( (val, i, arr) => val === arr[0] ) // true
You can use a Set to eliminate duplicates:
const nonUnique = a => new Set(a).size !== a.length;
console.log(nonUnique([1, 2, 3])); // false
console.log(nonUnique([1, 1, 5])); // true
console.log(nonUnique(['a', 'b', 'a', 'c'])); // true
console.log(nonUnique([10, 10, 10])); // true
One simple way would be create a Set of the unique values and compare size of Set to length of array
const hasDuplicates = (arr) => new Set(arr).size < arr.length ;
console.log(hasDuplicates([1, 2, 3]));
console.log(hasDuplicates([1, 1, 5]));
console.log(hasDuplicates(['a', 'b', 'a', 'c']));
console.log(hasDuplicates([10, 10, 10]));
This algorithm is pretty inefficient (O(n^2), brute force search), but it works:
function has_dupes(arr) {
return arr.some((x, i) => arr.includes(x, i+1));
}
console.log(has_dupes([1, 2, 3]));
console.log(has_dupes([1, 1, 5]));
console.log(has_dupes(['a', 'b', 'a', 'c']));
console.log(has_dupes([10, 10, 10]));
For every element x at some index i, we check whether the subarray starting at i+1 includes another value that's equal to x.
Using a for loop we can break the loop once we find a duplicate.
var a = [1, 2, 3] // false
var b = [1, 1, 5] // true
var c = ['a', 'b', 'a', 'c'] // true
var d = [10, 10, 10] // true
function diff(arr){
var diff = []
for(let i = 0; i<arr.length; i++){
if(diff.includes(arr[i])){
return true;//<-- break the loop
}else{
diff.push(arr[i]);
}
}
return false;
}
console.log(diff(a))
console.log(diff(b))
console.log(diff(c))
console.log(diff(d))
You could use a double for loop where one is the index of what is being looked for and the inner loop checking for a duplicate.
You can find all unique elements through lodash and just compare the size of both the arrays to get what you want.
a = [1, 2, 3]
a_uniq = _.uniq(a); //will return [1, 3]
console.log(a.length != a_uniq.length); //will return false
a = [1, 1, 3]
a_uniq = _.uniq(a); //will return [1, 3]
console.log(a.length != a_uniq.length); //will return true
Can test here quickly: https://codepen.io/travist/full/jrBjBz/
Reduce the array into an object with keys being the items. If the object's keys are a different length than the items length, there are duplicates.
This also gives you an indication of the number of duplicates.
const items1 = [1, 2, 3, 3, 4]
const items2 = [1, 2, 3, 3, 3, 3, 4]
const items3 = [1, 2, 3, 4]
const items4 = [undefined, undefined]
function dupCount(array) {
const obj = array.reduce((acc, item) => {
acc[item] = true;
return acc;
}, {})
return array.length - Object.keys(obj).length
}
console.log(dupCount(items1))
console.log(dupCount(items2))
console.log(dupCount(items3))
console.log(dupCount(items4))
function isSameArray(data, count) {
var result = false;
data.forEach(a => {
const filter = data.filter(f => f === a);
if (filter.length > count - 1) {
result = true;
return;
}
});
return result;
}
isSameArray([1, 2, 3], 2)
Add them to a set while checking using the find method
let items1 = [1, 2, 3, 3, 4];
let items2 = [1, 2, 3, 4];
let items3 = ['a', 'b', 'a', 'c']
let items4 = [0, 0]
let items5 = [undefined, undefined]
function hasDuplicate(array) {
const set = new Set()
return array.some(it => {
if (set.has(it)) {
return true
} else {
set.add(it);
return false;
}
})
}
console.log(hasDuplicate(items1))
console.log(hasDuplicate(items2))
console.log(hasDuplicate(items3))
console.log(hasDuplicate(items4))
console.log(hasDuplicate(items5))
You can loop it easily using for loop for example:-
function hasDuplicate(lst){
for(var i=0; i<lst.length; i++)
for(var j=i+1; j<lst.length;j++)
if(i!=j && lst[i] === lst[j])
return true;
return false;
}
var list1 = [1,1,5];
window.alert(hasDuplicate(list1)); //True
Array.some works the same as Array.every, except if the test passes true for one of the items in the array you're iterating over, execution stops and it returns true. Probably what you're looking for.
The following will help you in achieving the result which u gave as an example:
Array_is_true(int *a,int n)
{
int j=1,flag=0;
for(int i=0,i<n;i++)
{
j=i+1;
while(j<n;)
{
if(a[i]==a[j])
{ flag=1;j++;}
}
}
}
This is my array of arrays:
arr_1 = [1,2,3]
arr_2 = [4,5,6]
arr_3 = [7,8,9]
arr = [arr_1, arr_2, arr_3]
arr = [[1,2,3], [4,5,6], [7,8,9]]
What I want to do is push all elements like so that the final array is like the following and insert another element at the beginning of my array:
arr = [[i,1,2], [3,4,5], [6,7,8], [9]]
All sub-arrays must not be more than 3 elements.
Thanks for your help.
You could visit all inner arrays and unshift the leftover values from the previous loop.
var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
chunk = 3,
item = 'x',
i = 0,
temp = [item];
while (i < array.length) {
array[i].unshift(...temp);
temp = array[i].splice(chunk, array[i].length - chunk);
i++;
}
if (temp.length) {
array.push(temp);
}
console.log(array.map(a => a.join(' ')));
You can use the function reduce
var arr = [[1,2,3], [4,5,6], [7,8,9]],
newElem = "newOne",
all = [newElem, ...arr.reduce((a, c) => [...a, ...c], [])], // All together
// Build the desired output asking for the result of:
// element mod 3 === 0
result = all.reduce((a, c, i) => {
if (i % 3 === 0) a.push([c]);
else a[a.length - 1].push(c);
return a;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could move on each iteration last element from previous array to next one and if the last sub-array has more then 3 elements then remove the last one and add it to new array.
let arr_1 = [1, 2, 3],
arr_2 = [4, 5, 6],
arr_3 = [7, 8, 9],
arr = [arr_1, arr_2, arr_3]
setInterval(function() {
const last = arr.length - 1;
const newElement = parseInt(Math.random() * 30)
arr.forEach((a, i) => {
if(i == 0) a.unshift(newElement);
if(arr[i + 1]) arr[i + 1].unshift(a.pop())
else if(arr[last].length > 3) arr[last + 1] = [arr[last].pop()]
})
console.log(JSON.stringify(arr))
}, 1000)
You can do this quite succinctly with a simple unravel/ravel. It easy to adjust group size too.
let arr = [ [1,2,3], [4,5,6], [7,8,9]]
let newEl = 0
let groupSize = 3
var newArr = [];
var unravelled = arr.reduce((a, c) => a.concat(c), [newEl])
while(unravelled.length) newArr.push(unravelled.splice(0,groupSize));
console.log(newArr)
arr_1 = [1, 2, 3]
arr_2 = [4, 5, 6]
arr_3 = [7, 8, 9]
arr = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
function reassignChunk(x) {
// create an array which will be used to store unwrapped values
var newArray = [];
arr.forEach(function(elem) {
newArray.push(...elem); //using spread operator to unwrap values
});
newArray.unshift(x, limit)
var modArray = [];
var m, j, temparray, chunk = 3;
for (m = 0; m < newArray.length; m = m + limit) {
// creatinging new array using slice
modArray.push(newArray.slice(m, m + limit));
}
console.log(modArray)
}
reassignChunk(13, 3)
arr = [[i,1,2], [3,4,5], [6,7,8], [9]]
Assuming all your elements are numbers, you can do it like this:
Prepend i to the array
Flatten the array
Convert the array to a comma-separated string
Split the string into chunks of at most 3 numeric substrings (2 commas)
Convert the chunks back into arrays of numbers
const arr_1 = [1,2,3];
const arr_2 = [4,5,6];
const arr_3 = [7,8,9];
const i = 42;
const result = [i,...arr_1,...arr_2,...arr_3].join()
.match(/(?:[^,]+(,|$)){1,2}[^,]*/g).map( x => x.split(',').map(Number) )
;
console.log( result );
You may do your 2d unshifting simply as follows;
var arr_1 = [1,2,3],
arr_2 = [4,5,6],
arr_3 = [7,8,9],
arr = [arr_1, arr_2, arr_3],
us2d = (a2d,...is) => is.concat(...a2d)
.reduce((r,e,i) => (i%3 ? r[r.length-1].push(e)
: r.push([e]), r), []);
console.log(JSON.stringify(us2d(arr,0)));
console.log(JSON.stringify(us2d(arr,-2,-1,0)));