Related
I need to check a JavaScript array to see if there are any duplicate values. What's the easiest way to do this? I just need to find what the duplicated values are - I don't actually need their indexes or how many times they are duplicated.
I know I can loop through the array and check all the other values for a match, but it seems like there should be an easier way.
Similar question:
Get all unique values in a JavaScript array (remove duplicates)
You could sort the array and then run through it and then see if the next (or previous) index is the same as the current. Assuming your sort algorithm is good, this should be less than O(n2):
const findDuplicates = (arr) => {
let sorted_arr = arr.slice().sort(); // You can define the comparing function here.
// JS by default uses a crappy string compare.
// (we use slice to clone the array so the
// original array won't be modified)
let results = [];
for (let i = 0; i < sorted_arr.length - 1; i++) {
if (sorted_arr[i + 1] == sorted_arr[i]) {
results.push(sorted_arr[i]);
}
}
return results;
}
let duplicatedArray = [9, 9, 111, 2, 3, 4, 4, 5, 7];
console.log(`The duplicates in ${duplicatedArray} are ${findDuplicates(duplicatedArray)}`);
In case, if you are to return as a function for duplicates. This is for similar type of case.
Reference: https://stackoverflow.com/a/57532964/8119511
If you want to elimate the duplicates, try this great solution:
function eliminateDuplicates(arr) {
var i,
len = arr.length,
out = [],
obj = {};
for (i = 0; i < len; i++) {
obj[arr[i]] = 0;
}
for (i in obj) {
out.push(i);
}
return out;
}
console.log(eliminateDuplicates([1,6,7,3,6,8,1,3,4,5,1,7,2,6]))
Source:
http://dreaminginjavascript.wordpress.com/2008/08/22/eliminating-duplicates/
This is my answer from the duplicate thread (!):
When writing this entry 2014 - all examples were for-loops or jQuery. JavaScript has the perfect tools for this: sort, map and reduce.
Find duplicate items
var names = ['Mike', 'Matt', 'Nancy', 'Adam', 'Jenny', 'Nancy', 'Carl']
const uniq = names
.map((name) => {
return {
count: 1,
name: name
};
})
.reduce((result, b) => {
result[b.name] = (result[b.name] || 0) + b.count;
return result;
}, {});
const duplicates = Object.keys(uniq).filter((a) => uniq[a] > 1);
console.log(duplicates); // [ 'Nancy' ]
More functional syntax:
#Dmytro-Laptin pointed out some code that can be removed. This is a more compact version of the same code. Using some ES6 tricks and higher-order functions:
const names = ['Mike', 'Matt', 'Nancy', 'Adam', 'Jenny', 'Nancy', 'Carl'];
const count = names =>
names.reduce((result, value) => ({ ...result,
[value]: (result[value] || 0) + 1
}), {}); // don't forget to initialize the accumulator
const duplicates = dict =>
Object.keys(dict).filter((a) => dict[a] > 1);
console.log(count(names)); // { Mike: 1, Matt: 1, Nancy: 2, Adam: 1, Jenny: 1, Carl: 1 }
console.log(duplicates(count(names))); // [ 'Nancy' ]
UPDATED: Short one-liner to get the duplicates:
[1, 2, 2, 4, 3, 4].filter((e, i, a) => a.indexOf(e) !== i) // [2, 4]
To get the array without duplicates simply invert the condition:
[1, 2, 2, 4, 3, 4].filter((e, i, a) => a.indexOf(e) === i) // [1, 2, 3, 4]
Note that this answerβs main goal is to be short. If you need something performant for a big array, one possible solution is to sort your array first (if it is sortable) then do the following to get the same kind of results as above:
myHugeSortedArray.filter((e, i, a) => a[i-1] === e)
Here is an example for a 1 000 000 integers array:
const myHugeIntArrayWithDuplicates =
[...Array(1_000_000).keys()]
// adding two 0 and four 9 duplicates
.fill(0, 2, 4).fill(9, 10, 14)
console.time("time")
console.log(
myHugeIntArrayWithDuplicates
// a possible sorting method for integers
.sort((a, b) => a > b ? 1 : -1)
.filter((e, i, a) => a[i-1] === e)
)
console.timeEnd("time")
On my AMD Ryzen 7 5700G dev machine it outputs:
[ 0, 0, 9, 9, 9, 9 ]
time: 22.738ms
As pointed out in the comments both the short solution and the performant solution will return an array with several time the same duplicate if it occurs more than once in the original array:
[1, 1, 1, 2, 2, 2, 2].filter((e, i, a) => a.indexOf(e) !== i) // [1, 1, 2, 2, 2]
If unique duplicates are wanted then a function like
function duplicates(arr) {
return [...new Set(arr.filter((e, i, a) => a.indexOf(e) !== i))]
}
can be used so that duplicates([1, 1, 1, 2, 2, 2, 2]) returns [1, 2].
When all you need is to check that there are no duplicates as asked in this question you can use the every() method:
[1, 2, 3].every((e, i, a) => a.indexOf(e) === i) // true
[1, 2, 1].every((e, i, a) => a.indexOf(e) === i) // false
Note that every() doesn't work for IE 8 and below.
Find duplicate values in an array
This should be one of the shortest ways to actually find duplicate values in an array. As specifically asked for by the OP, this does not remove duplicates but finds them.
var input = [1, 2, 3, 1, 3, 1];
var duplicates = input.reduce(function(acc, el, i, arr) {
if (arr.indexOf(el) !== i && acc.indexOf(el) < 0) acc.push(el); return acc;
}, []);
document.write(duplicates); // = 1,3 (actual array == [1, 3])
This doesn't need sorting or any third party framework. It also doesn't need manual loops. It works with every value indexOf() (or to be clearer: the strict comparision operator) supports.
Because of reduce() and indexOf() it needs at least IE 9.
You can add this function, or tweak it and add it to Javascript's Array prototype:
Array.prototype.unique = function () {
var r = new Array();
o:for(var i = 0, n = this.length; i < n; i++)
{
for(var x = 0, y = r.length; x < y; x++)
{
if(r[x]==this[i])
{
alert('this is a DUPE!');
continue o;
}
}
r[r.length] = this[i];
}
return r;
}
var arr = [1,2,2,3,3,4,5,6,2,3,7,8,5,9];
var unique = arr.unique();
alert(unique);
UPDATED: The following uses an optimized combined strategy. It optimizes primitive lookups to benefit from hash O(1) lookup time (running unique on an array of primitives is O(n)). Object lookups are optimized by tagging objects with a unique id while iterating through so so identifying duplicate objects is also O(1) per item and O(n) for the whole list. The only exception is items that are frozen, but those are rare and a fallback is provided using an array and indexOf.
var unique = function(){
var hasOwn = {}.hasOwnProperty,
toString = {}.toString,
uids = {};
function uid(){
var key = Math.random().toString(36).slice(2);
return key in uids ? uid() : uids[key] = key;
}
function unique(array){
var strings = {}, numbers = {}, others = {},
tagged = [], failed = [],
count = 0, i = array.length,
item, type;
var id = uid();
while (i--) {
item = array[i];
type = typeof item;
if (item == null || type !== 'object' && type !== 'function') {
// primitive
switch (type) {
case 'string': strings[item] = true; break;
case 'number': numbers[item] = true; break;
default: others[item] = item; break;
}
} else {
// object
if (!hasOwn.call(item, id)) {
try {
item[id] = true;
tagged[count++] = item;
} catch (e){
if (failed.indexOf(item) === -1)
failed[failed.length] = item;
}
}
}
}
// remove the tags
while (count--)
delete tagged[count][id];
tagged = tagged.concat(failed);
count = tagged.length;
// append primitives to results
for (i in strings)
if (hasOwn.call(strings, i))
tagged[count++] = i;
for (i in numbers)
if (hasOwn.call(numbers, i))
tagged[count++] = +i;
for (i in others)
if (hasOwn.call(others, i))
tagged[count++] = others[i];
return tagged;
}
return unique;
}();
If you have ES6 Collections available, then there is a much simpler and significantly faster version. (shim for IE9+ and other browsers here: https://github.com/Benvie/ES6-Harmony-Collections-Shim)
function unique(array){
var seen = new Set;
return array.filter(function(item){
if (!seen.has(item)) {
seen.add(item);
return true;
}
});
}
var a = ["a","a","b","c","c"];
a.filter(function(value,index,self){ return (self.indexOf(value) !== index )})
This should get you what you want, Just the duplicates.
function find_duplicates(arr) {
var len=arr.length,
out=[],
counts={};
for (var i=0;i<len;i++) {
var item = arr[i];
counts[item] = counts[item] >= 1 ? counts[item] + 1 : 1;
if (counts[item] === 2) {
out.push(item);
}
}
return out;
}
find_duplicates(['one',2,3,4,4,4,5,6,7,7,7,'pig','one']); // -> ['one',4,7] in no particular order.
Find non-unique values from 3 arrays (or more):
ES2015
// π©π© π© π© π©
var arr = [1,2,2,3,3,4,5,6,2,3,7,8,5,22],
arr2 = [1,2,511,12,50],
arr3 = [22,0],
merged,
nonUnique;
// Combine all the arrays to a single one
merged = arr.concat(arr2, arr3)
// create a new (dirty) Array with only the non-unique items
nonUnique = merged.filter((item,i) => merged.includes(item, i+1))
// Cleanup - remove duplicate & empty items items
nonUnique = [...new Set(nonUnique)]
console.log(nonUnique)
PRE-ES2015:
In the below example I chose to superimpose a unique method on top of the Array prototype, allowing access from everywhere and has more "declarative" syntax. I do not recommend this approach on large projects, since it might very well collide with another method with the same custom name.
Array.prototype.unique = function () {
var arr = this.sort(), i=arr.length; // input must be sorted for this to work
while(i--)
arr[i] === arr[i-1] && arr.splice(i,1) // remove duplicate item
return arr
}
Array.prototype.nonunique = function () {
var arr = this.sort(), i=arr.length, res = []; // input must be sorted for this to work
while(i--)
arr[i] === arr[i-1] && (res.indexOf(arr[i]) == -1) && res.push(arr[i])
return res
}
// π©π© π© π© π©
var arr = [1,2,2,3,3,4,5,6,2,3,7,8,5,22],
arr2 = [1,2,511,12,50],
arr3 = [22,0],
// merge all arrays & call custom Array Prototype - "unique"
unique = arr.concat(arr2, arr3).unique(),
nonunique = arr.concat(arr2, arr3).nonunique()
console.log(unique) // [1,12,2,22,3,4,5,50,511,6,7,8]
console.log(nonunique) // [1,12,2,22,3,4,5,50,511,6,7,8]
using underscore.js
function hasDuplicate(arr){
return (arr.length != _.uniq(arr).length);
}
The simplest and quickest way is to use the Set object:
const numbers = [1, 2, 3, 2, 4, 5, 5, 6];
const set = new Set(numbers);
const duplicates = numbers.filter(item => {
if (set.has(item)) {
set.delete(item);
return false;
} else {
return true;
}
});
// OR more concisely
const duplicates = numbers.filter(item => !set.delete(item));
console.log(duplicates);
// [ 2, 5 ]
This is my proposal (ES6):
let a = [1, 2, 3, 4, 2, 2, 4, 1, 5, 6]
let b = [...new Set(a.sort().filter((o, i) => o !== undefined && a[i + 1] !== undefined && o === a[i + 1]))]
// b is now [1, 2, 4]
Here's the simplest solution I could think of:
const arr = [-1, 2, 2, 2, 0, 0, 0, 500, -1, 'a', 'a', 'a']
const filtered = arr.filter((el, index) => arr.indexOf(el) !== index)
// => filtered = [ 2, 2, 0, 0, -1, 'a', 'a' ]
const duplicates = [...new Set(filtered)]
console.log(duplicates)
// => [ 2, 0, -1, 'a' ]
That's it.
Note:
It works with any numbers including 0, strings and negative numbers e.g. -1 -
Related question: Get all unique values in a JavaScript array (remove duplicates)
The original array arr is preserved (filter returns the new array instead of modifying the original)
The filtered array contains all duplicates; it can also contain more than 1 same value (e.g. our filtered array here is [ 2, 2, 0, 0, -1, 'a', 'a' ])
If you want to get only values that are duplicated (you don't want to have multiple duplicates with the same value) you can use [...new Set(filtered)] (ES6 has an object Set which can store only unique values)
Hope this helps.
Here is mine simple and one line solution.
It searches not unique elements first, then makes found array unique with the use of Set.
So we have array of duplicates in the end.
var array = [1, 2, 2, 3, 3, 4, 5, 6, 2, 3, 7, 8, 5, 22, 1, 2, 511, 12, 50, 22];
console.log([...new Set(
array.filter((value, index, self) => self.indexOf(value) !== index))]
);
Shortest vanilla JS:
[1,1,2,2,2,3].filter((v,i,a) => a.indexOf(v) !== i) // [1, 2, 2]
one liner simple way
var arr = [9,1,2,4,3,4,9]
console.log(arr.filter((ele,indx)=>indx!==arr.indexOf(ele))) //get the duplicates
console.log(arr.filter((ele,indx)=>indx===arr.indexOf(ele))) //remove the duplicates
var a = [324,3,32,5,52,2100,1,20,2,3,3,2,2,2,1,1,1].sort();
a.filter(function(v,i,o){return i&&v!==o[i-1]?v:0;});
or when added to the prototyp.chain of Array
//copy and paste: without error handling
Array.prototype.unique =
function(){return this.sort().filter(function(v,i,o){return i&&v!==o[i-1]?v:0;});}
See here: https://gist.github.com/1305056
Fast and elegant way using es6 object destructuring and reduce
It runs in O(n) (1 iteration over the array) and doesn't repeat values that appear more than 2 times
const arr = ['hi', 'hi', 'hi', 'bye', 'bye', 'asd']
const {
dup
} = arr.reduce(
(acc, curr) => {
acc.items[curr] = acc.items[curr] ? acc.items[curr] += 1 : 1
if (acc.items[curr] === 2) acc.dup.push(curr)
return acc
}, {
items: {},
dup: []
},
)
console.log(dup)
// ['hi', 'bye']
You can use filter method and indexOf() to get all the duplicate values
function duplicate(arr) {
return duplicateArray = arr.filter((item, index) => arr.indexOf(item) !== index)
}
arr.indexOf(item) will always return the first index at which a given element can be
found
ES5 only (i.e., it needs a filter() polyfill for IE8 and below):
var arrayToFilter = [ 4, 5, 5, 5, 2, 1, 3, 1, 1, 2, 1, 3 ];
arrayToFilter.
sort().
filter( function(me,i,arr){
return (i===0) || ( me !== arr[i-1] );
});
Here is a very light and easy way:
var codes = dc_1.split(',');
var i = codes.length;
while (i--) {
if (codes.indexOf(codes[i]) != i) {
codes.splice(i,1);
}
}
ES6 offers the Set data structure which is basically an array that doesn't accept duplicates.
With the Set data structure, there's a very easy way to find duplicates in an array (using only one loop).
Here's my code
function findDuplicate(arr) {
var set = new Set();
var duplicates = new Set();
for (let i = 0; i< arr.length; i++) {
var size = set.size;
set.add(arr[i]);
if (set.size === size) {
duplicates.add(arr[i]);
}
}
return duplicates;
}
With ES6 (or using Babel or Typescipt) you can simply do:
var duplicates = myArray.filter(i => myArray.filter(ii => ii === i).length > 1);
https://es6console.com/j58euhbt/
Simple code with ES6 syntax (return sorted array of duplicates):
let duplicates = a => {d=[]; a.sort((a,b) => a-b).reduce((a,b)=>{a==b&&!d.includes(a)&&d.push(a); return b}); return d};
How to use:
duplicates([1,2,3,10,10,2,3,3,10]);
I have just figured out a simple way to achieve this using an Array filter
var list = [9, 9, 111, 2, 3, 4, 4, 5, 7];
// Filter 1: to find all duplicates elements
var duplicates = list.filter(function(value,index,self) {
return self.indexOf(value) !== self.lastIndexOf(value) && self.indexOf(value) === index;
});
console.log(duplicates);
This answer might also be helpful, it leverages js reduce operator/method to remove duplicates from array.
const result = [1, 2, 2, 3, 3, 3, 3].reduce((x, y) => x.includes(y) ? x : [...x, y], []);
console.log(result);
Higher ranked answers have a few inherent issues including the use of legacy javascript, incorrect ordering or with only support for 2 duplicated items.
Here's a modern solution which fixes those problems:
const arrayNonUniq = array => {
if (!Array.isArray(array)) {
throw new TypeError("An array must be provided!")
}
return array.filter((value, index) => array.indexOf(value) === index && array.lastIndexOf(value) !== index)
}
arrayNonUniq([1, 1, 2, 3, 3])
//=> [1, 3]
arrayNonUniq(["foo", "foo", "bar", "foo"])
//=> ['foo']
You can also use the npm package array-non-uniq.
The following function (a variation of the eliminateDuplicates function already mentioned) seems to do the trick, returning test2,1,7,5 for the input ["test", "test2", "test2", 1, 1, 1, 2, 3, 4, 5, 6, 7, 7, 10, 22, 43, 1, 5, 8]
Note that the problem is stranger in JavaScript than in most other languages, because a JavaScript array can hold just about anything. Note that solutions that use sorting might need to provide an appropriate sorting function--I haven't tried that route yet.
This particular implementation works for (at least) strings and numbers.
function findDuplicates(arr) {
var i,
len=arr.length,
out=[],
obj={};
for (i=0;i<len;i++) {
if (obj[arr[i]] != null) {
if (!obj[arr[i]]) {
out.push(arr[i]);
obj[arr[i]] = 1;
}
} else {
obj[arr[i]] = 0;
}
}
return out;
}
var arr = [2, 1, 2, 2, 4, 4, 2, 5];
function returnDuplicates(arr) {
return arr.reduce(function(dupes, val, i) {
if (arr.indexOf(val) !== i && dupes.indexOf(val) === -1) {
dupes.push(val);
}
return dupes;
}, []);
}
alert(returnDuplicates(arr));
This function avoids the sorting step and uses the reduce() method to push duplicates to a new array if it doesn't already exist in it.
Array.prototype.reverse reverses the contents of an array in place (with mutation)...
Is there a similarly simple strategy for reversing an array without altering the contents of the original array (without mutation)?
You can use slice() to make a copy then reverse() it
var newarray = array.slice().reverse();
var array = ['a', 'b', 'c', 'd', 'e'];
var newarray = array.slice().reverse();
console.log('a', array);
console.log('na', newarray);
In ES6:
const newArray = [...array].reverse()
Another ES6 variant:
We can also use .reduceRight() to create a reversed array without actually reversing it.
let A = ['a', 'b', 'c', 'd', 'e', 'f'];
let B = A.reduceRight((a, c) => (a.push(c), a), []);
console.log(B);
Useful Resources:
Array.prototype.reduceRight()
Arrow Functions
Comma Operator
const originalArray = ['a', 'b', 'c', 'd', 'e', 'f'];
const newArray = Array.from(originalArray).reverse();
console.log(newArray);
There are multiple ways of reversing an array without modifying. Two of them are
var array = [1,2,3,4,5,6,7,8,9,10];
// Using Splice
var reverseArray1 = array.splice().reverse(); // Fastest
// Using spread operator
var reverseArray2 = [...array].reverse();
// Using for loop
var reverseArray3 = [];
for(var i = array.length-1; i>=0; i--) {
reverseArray.push(array[i]);
}
Performance test http://jsben.ch/guftu
Try this recursive solution:
const reverse = ([head, ...tail]) =>
tail.length === 0
? [head] // Base case -- cannot reverse a single element.
: [...reverse(tail), head] // Recursive case
reverse([1]); // [1]
reverse([1,2,3]); // [3,2,1]
reverse('hello').join(''); // 'olleh' -- Strings too!
An ES6 alternative using .reduce() and spreading.
const foo = [1, 2, 3, 4];
const bar = foo.reduce((acc, b) => ([b, ...acc]), []);
Basically what it does is create a new array with the next element in foo, and spreading the accumulated array for each iteration after b.
[]
[1] => [1]
[2, ...[1]] => [2, 1]
[3, ...[2, 1]] => [3, 2, 1]
[4, ...[3, 2, 1]] => [4, 3, 2, 1]
Alternatively .reduceRight() as mentioned above here, but without the .push() mutation.
const baz = foo.reduceRight((acc, b) => ([...acc, b]), []);
const arrayCopy = Object.assign([], array).reverse()
This solution:
-Successfully copies the array
-Doesn't mutate the original array
-Looks like it's doing what it is doing
There's a new tc39 proposal, which adds a toReversed method to Array that returns a copy of the array and doesn't modify the original.
Example from the proposal:
const sequence = [1, 2, 3];
sequence.toReversed(); // => [3, 2, 1]
sequence; // => [1, 2, 3]
As it's currently in stage 3, it will likely be implemented in browser engines soon, but in the meantime a polyfill is available here or in core-js.
Reversing in place with variable swap just for demonstrative purposes (but you need a copy if you don't want to mutate)
const myArr = ["a", "b", "c", "d"];
const copy = [...myArr];
for (let i = 0; i < (copy.length - 1) / 2; i++) {
const lastIndex = copy.length - 1 - i;
[copy[i], copy[lastIndex]] = [copy[lastIndex], copy[i]]
}
Jumping into 2022, and here's the most efficient solution today (highest-performing, and no extra memory usage).
For any ArrayLike type, the fastest way to reverse is logically, by wrapping it into a reversed iterable:
function reverse<T>(input: ArrayLike<T>): Iterable<T> {
return {
[Symbol.iterator](): Iterator<T> {
let i = input.length;
return {
next(): IteratorResult<T> {
return i
? {value: input[--i], done: false}
: {value: undefined, done: true};
},
};
},
};
}
This way you can reverse-iterate through any Array, string or Buffer, without any extra copy or processing for the reversed data:
for(const a of reverse([1, 2, 3])) {
console.log(a); //=> 3 2 1
}
It is the fastest approach, because you do not copy the data, and do no processing at all, you just reverse it logically.
Is there a similarly simple strategy for reversing an array without altering the contents of the original array (without mutation) ?
Yes, there is a way to achieve this by using to[Operation] that return a new collection with the operation applied (This is currently at stage 3, will be available soon).
Implementation will be like :
const arr = [5, 4, 3, 2, 1];
const reversedArr = arr.toReverse();
console.log(arr); // [5, 4, 3, 2, 1]
console.log(reversedArr); // [1, 2, 3, 4, 5]
Not the best solution but it works
Array.prototype.myNonMutableReverse = function () {
const reversedArr = [];
for (let i = this.length - 1; i >= 0; i--) reversedArr.push(this[i]);
return reversedArr;
};
const a = [1, 2, 3, 4, 5, 6, 7, 8];
const b = a.myNonMutableReverse();
console.log("a",a);
console.log("////////")
console.log("b",b);
INTO plain Javascript:
function reverseArray(arr, num) {
var newArray = [];
for (let i = num; i <= arr.length - 1; i++) {
newArray.push(arr[i]);
}
return newArray;
}
es6:
const reverseArr = [1,2,3,4].sort(()=>1)
Array.prototype.reverse reverses the contents of an array in place (with mutation)...
Is there a similarly simple strategy for reversing an array without altering the contents of the original array (without mutation)?
You can use slice() to make a copy then reverse() it
var newarray = array.slice().reverse();
var array = ['a', 'b', 'c', 'd', 'e'];
var newarray = array.slice().reverse();
console.log('a', array);
console.log('na', newarray);
In ES6:
const newArray = [...array].reverse()
Another ES6 variant:
We can also use .reduceRight() to create a reversed array without actually reversing it.
let A = ['a', 'b', 'c', 'd', 'e', 'f'];
let B = A.reduceRight((a, c) => (a.push(c), a), []);
console.log(B);
Useful Resources:
Array.prototype.reduceRight()
Arrow Functions
Comma Operator
const originalArray = ['a', 'b', 'c', 'd', 'e', 'f'];
const newArray = Array.from(originalArray).reverse();
console.log(newArray);
There are multiple ways of reversing an array without modifying. Two of them are
var array = [1,2,3,4,5,6,7,8,9,10];
// Using Splice
var reverseArray1 = array.splice().reverse(); // Fastest
// Using spread operator
var reverseArray2 = [...array].reverse();
// Using for loop
var reverseArray3 = [];
for(var i = array.length-1; i>=0; i--) {
reverseArray.push(array[i]);
}
Performance test http://jsben.ch/guftu
Try this recursive solution:
const reverse = ([head, ...tail]) =>
tail.length === 0
? [head] // Base case -- cannot reverse a single element.
: [...reverse(tail), head] // Recursive case
reverse([1]); // [1]
reverse([1,2,3]); // [3,2,1]
reverse('hello').join(''); // 'olleh' -- Strings too!
An ES6 alternative using .reduce() and spreading.
const foo = [1, 2, 3, 4];
const bar = foo.reduce((acc, b) => ([b, ...acc]), []);
Basically what it does is create a new array with the next element in foo, and spreading the accumulated array for each iteration after b.
[]
[1] => [1]
[2, ...[1]] => [2, 1]
[3, ...[2, 1]] => [3, 2, 1]
[4, ...[3, 2, 1]] => [4, 3, 2, 1]
Alternatively .reduceRight() as mentioned above here, but without the .push() mutation.
const baz = foo.reduceRight((acc, b) => ([...acc, b]), []);
const arrayCopy = Object.assign([], array).reverse()
This solution:
-Successfully copies the array
-Doesn't mutate the original array
-Looks like it's doing what it is doing
There's a new tc39 proposal, which adds a toReversed method to Array that returns a copy of the array and doesn't modify the original.
Example from the proposal:
const sequence = [1, 2, 3];
sequence.toReversed(); // => [3, 2, 1]
sequence; // => [1, 2, 3]
As it's currently in stage 3, it will likely be implemented in browser engines soon, but in the meantime a polyfill is available here or in core-js.
Reversing in place with variable swap just for demonstrative purposes (but you need a copy if you don't want to mutate)
const myArr = ["a", "b", "c", "d"];
const copy = [...myArr];
for (let i = 0; i < (copy.length - 1) / 2; i++) {
const lastIndex = copy.length - 1 - i;
[copy[i], copy[lastIndex]] = [copy[lastIndex], copy[i]]
}
Jumping into 2022, and here's the most efficient solution today (highest-performing, and no extra memory usage).
For any ArrayLike type, the fastest way to reverse is logically, by wrapping it into a reversed iterable:
function reverse<T>(input: ArrayLike<T>): Iterable<T> {
return {
[Symbol.iterator](): Iterator<T> {
let i = input.length;
return {
next(): IteratorResult<T> {
return i
? {value: input[--i], done: false}
: {value: undefined, done: true};
},
};
},
};
}
This way you can reverse-iterate through any Array, string or Buffer, without any extra copy or processing for the reversed data:
for(const a of reverse([1, 2, 3])) {
console.log(a); //=> 3 2 1
}
It is the fastest approach, because you do not copy the data, and do no processing at all, you just reverse it logically.
Is there a similarly simple strategy for reversing an array without altering the contents of the original array (without mutation) ?
Yes, there is a way to achieve this by using to[Operation] that return a new collection with the operation applied (This is currently at stage 3, will be available soon).
Implementation will be like :
const arr = [5, 4, 3, 2, 1];
const reversedArr = arr.toReverse();
console.log(arr); // [5, 4, 3, 2, 1]
console.log(reversedArr); // [1, 2, 3, 4, 5]
Not the best solution but it works
Array.prototype.myNonMutableReverse = function () {
const reversedArr = [];
for (let i = this.length - 1; i >= 0; i--) reversedArr.push(this[i]);
return reversedArr;
};
const a = [1, 2, 3, 4, 5, 6, 7, 8];
const b = a.myNonMutableReverse();
console.log("a",a);
console.log("////////")
console.log("b",b);
INTO plain Javascript:
function reverseArray(arr, num) {
var newArray = [];
for (let i = num; i <= arr.length - 1; i++) {
newArray.push(arr[i]);
}
return newArray;
}
es6:
const reverseArr = [1,2,3,4].sort(()=>1)
I need to check a JavaScript array to see if there are any duplicate values. What's the easiest way to do this? I just need to find what the duplicated values are - I don't actually need their indexes or how many times they are duplicated.
I know I can loop through the array and check all the other values for a match, but it seems like there should be an easier way.
Similar question:
Get all unique values in a JavaScript array (remove duplicates)
You could sort the array and then run through it and then see if the next (or previous) index is the same as the current. Assuming your sort algorithm is good, this should be less than O(n2):
const findDuplicates = (arr) => {
let sorted_arr = arr.slice().sort(); // You can define the comparing function here.
// JS by default uses a crappy string compare.
// (we use slice to clone the array so the
// original array won't be modified)
let results = [];
for (let i = 0; i < sorted_arr.length - 1; i++) {
if (sorted_arr[i + 1] == sorted_arr[i]) {
results.push(sorted_arr[i]);
}
}
return results;
}
let duplicatedArray = [9, 9, 111, 2, 3, 4, 4, 5, 7];
console.log(`The duplicates in ${duplicatedArray} are ${findDuplicates(duplicatedArray)}`);
In case, if you are to return as a function for duplicates. This is for similar type of case.
Reference: https://stackoverflow.com/a/57532964/8119511
If you want to elimate the duplicates, try this great solution:
function eliminateDuplicates(arr) {
var i,
len = arr.length,
out = [],
obj = {};
for (i = 0; i < len; i++) {
obj[arr[i]] = 0;
}
for (i in obj) {
out.push(i);
}
return out;
}
console.log(eliminateDuplicates([1,6,7,3,6,8,1,3,4,5,1,7,2,6]))
Source:
http://dreaminginjavascript.wordpress.com/2008/08/22/eliminating-duplicates/
This is my answer from the duplicate thread (!):
When writing this entry 2014 - all examples were for-loops or jQuery. JavaScript has the perfect tools for this: sort, map and reduce.
Find duplicate items
var names = ['Mike', 'Matt', 'Nancy', 'Adam', 'Jenny', 'Nancy', 'Carl']
const uniq = names
.map((name) => {
return {
count: 1,
name: name
};
})
.reduce((result, b) => {
result[b.name] = (result[b.name] || 0) + b.count;
return result;
}, {});
const duplicates = Object.keys(uniq).filter((a) => uniq[a] > 1);
console.log(duplicates); // [ 'Nancy' ]
More functional syntax:
#Dmytro-Laptin pointed out some code that can be removed. This is a more compact version of the same code. Using some ES6 tricks and higher-order functions:
const names = ['Mike', 'Matt', 'Nancy', 'Adam', 'Jenny', 'Nancy', 'Carl'];
const count = names =>
names.reduce((result, value) => ({ ...result,
[value]: (result[value] || 0) + 1
}), {}); // don't forget to initialize the accumulator
const duplicates = dict =>
Object.keys(dict).filter((a) => dict[a] > 1);
console.log(count(names)); // { Mike: 1, Matt: 1, Nancy: 2, Adam: 1, Jenny: 1, Carl: 1 }
console.log(duplicates(count(names))); // [ 'Nancy' ]
UPDATED: Short one-liner to get the duplicates:
[1, 2, 2, 4, 3, 4].filter((e, i, a) => a.indexOf(e) !== i) // [2, 4]
To get the array without duplicates simply invert the condition:
[1, 2, 2, 4, 3, 4].filter((e, i, a) => a.indexOf(e) === i) // [1, 2, 3, 4]
Note that this answerβs main goal is to be short. If you need something performant for a big array, one possible solution is to sort your array first (if it is sortable) then do the following to get the same kind of results as above:
myHugeSortedArray.filter((e, i, a) => a[i-1] === e)
Here is an example for a 1 000 000 integers array:
const myHugeIntArrayWithDuplicates =
[...Array(1_000_000).keys()]
// adding two 0 and four 9 duplicates
.fill(0, 2, 4).fill(9, 10, 14)
console.time("time")
console.log(
myHugeIntArrayWithDuplicates
// a possible sorting method for integers
.sort((a, b) => a > b ? 1 : -1)
.filter((e, i, a) => a[i-1] === e)
)
console.timeEnd("time")
On my AMD Ryzen 7 5700G dev machine it outputs:
[ 0, 0, 9, 9, 9, 9 ]
time: 22.738ms
As pointed out in the comments both the short solution and the performant solution will return an array with several time the same duplicate if it occurs more than once in the original array:
[1, 1, 1, 2, 2, 2, 2].filter((e, i, a) => a.indexOf(e) !== i) // [1, 1, 2, 2, 2]
If unique duplicates are wanted then a function like
function duplicates(arr) {
return [...new Set(arr.filter((e, i, a) => a.indexOf(e) !== i))]
}
can be used so that duplicates([1, 1, 1, 2, 2, 2, 2]) returns [1, 2].
When all you need is to check that there are no duplicates as asked in this question you can use the every() method:
[1, 2, 3].every((e, i, a) => a.indexOf(e) === i) // true
[1, 2, 1].every((e, i, a) => a.indexOf(e) === i) // false
Note that every() doesn't work for IE 8 and below.
Find duplicate values in an array
This should be one of the shortest ways to actually find duplicate values in an array. As specifically asked for by the OP, this does not remove duplicates but finds them.
var input = [1, 2, 3, 1, 3, 1];
var duplicates = input.reduce(function(acc, el, i, arr) {
if (arr.indexOf(el) !== i && acc.indexOf(el) < 0) acc.push(el); return acc;
}, []);
document.write(duplicates); // = 1,3 (actual array == [1, 3])
This doesn't need sorting or any third party framework. It also doesn't need manual loops. It works with every value indexOf() (or to be clearer: the strict comparision operator) supports.
Because of reduce() and indexOf() it needs at least IE 9.
You can add this function, or tweak it and add it to Javascript's Array prototype:
Array.prototype.unique = function () {
var r = new Array();
o:for(var i = 0, n = this.length; i < n; i++)
{
for(var x = 0, y = r.length; x < y; x++)
{
if(r[x]==this[i])
{
alert('this is a DUPE!');
continue o;
}
}
r[r.length] = this[i];
}
return r;
}
var arr = [1,2,2,3,3,4,5,6,2,3,7,8,5,9];
var unique = arr.unique();
alert(unique);
UPDATED: The following uses an optimized combined strategy. It optimizes primitive lookups to benefit from hash O(1) lookup time (running unique on an array of primitives is O(n)). Object lookups are optimized by tagging objects with a unique id while iterating through so so identifying duplicate objects is also O(1) per item and O(n) for the whole list. The only exception is items that are frozen, but those are rare and a fallback is provided using an array and indexOf.
var unique = function(){
var hasOwn = {}.hasOwnProperty,
toString = {}.toString,
uids = {};
function uid(){
var key = Math.random().toString(36).slice(2);
return key in uids ? uid() : uids[key] = key;
}
function unique(array){
var strings = {}, numbers = {}, others = {},
tagged = [], failed = [],
count = 0, i = array.length,
item, type;
var id = uid();
while (i--) {
item = array[i];
type = typeof item;
if (item == null || type !== 'object' && type !== 'function') {
// primitive
switch (type) {
case 'string': strings[item] = true; break;
case 'number': numbers[item] = true; break;
default: others[item] = item; break;
}
} else {
// object
if (!hasOwn.call(item, id)) {
try {
item[id] = true;
tagged[count++] = item;
} catch (e){
if (failed.indexOf(item) === -1)
failed[failed.length] = item;
}
}
}
}
// remove the tags
while (count--)
delete tagged[count][id];
tagged = tagged.concat(failed);
count = tagged.length;
// append primitives to results
for (i in strings)
if (hasOwn.call(strings, i))
tagged[count++] = i;
for (i in numbers)
if (hasOwn.call(numbers, i))
tagged[count++] = +i;
for (i in others)
if (hasOwn.call(others, i))
tagged[count++] = others[i];
return tagged;
}
return unique;
}();
If you have ES6 Collections available, then there is a much simpler and significantly faster version. (shim for IE9+ and other browsers here: https://github.com/Benvie/ES6-Harmony-Collections-Shim)
function unique(array){
var seen = new Set;
return array.filter(function(item){
if (!seen.has(item)) {
seen.add(item);
return true;
}
});
}
var a = ["a","a","b","c","c"];
a.filter(function(value,index,self){ return (self.indexOf(value) !== index )})
This should get you what you want, Just the duplicates.
function find_duplicates(arr) {
var len=arr.length,
out=[],
counts={};
for (var i=0;i<len;i++) {
var item = arr[i];
counts[item] = counts[item] >= 1 ? counts[item] + 1 : 1;
if (counts[item] === 2) {
out.push(item);
}
}
return out;
}
find_duplicates(['one',2,3,4,4,4,5,6,7,7,7,'pig','one']); // -> ['one',4,7] in no particular order.
Find non-unique values from 3 arrays (or more):
ES2015
// π©π© π© π© π©
var arr = [1,2,2,3,3,4,5,6,2,3,7,8,5,22],
arr2 = [1,2,511,12,50],
arr3 = [22,0],
merged,
nonUnique;
// Combine all the arrays to a single one
merged = arr.concat(arr2, arr3)
// create a new (dirty) Array with only the non-unique items
nonUnique = merged.filter((item,i) => merged.includes(item, i+1))
// Cleanup - remove duplicate & empty items items
nonUnique = [...new Set(nonUnique)]
console.log(nonUnique)
PRE-ES2015:
In the below example I chose to superimpose a unique method on top of the Array prototype, allowing access from everywhere and has more "declarative" syntax. I do not recommend this approach on large projects, since it might very well collide with another method with the same custom name.
Array.prototype.unique = function () {
var arr = this.sort(), i=arr.length; // input must be sorted for this to work
while(i--)
arr[i] === arr[i-1] && arr.splice(i,1) // remove duplicate item
return arr
}
Array.prototype.nonunique = function () {
var arr = this.sort(), i=arr.length, res = []; // input must be sorted for this to work
while(i--)
arr[i] === arr[i-1] && (res.indexOf(arr[i]) == -1) && res.push(arr[i])
return res
}
// π©π© π© π© π©
var arr = [1,2,2,3,3,4,5,6,2,3,7,8,5,22],
arr2 = [1,2,511,12,50],
arr3 = [22,0],
// merge all arrays & call custom Array Prototype - "unique"
unique = arr.concat(arr2, arr3).unique(),
nonunique = arr.concat(arr2, arr3).nonunique()
console.log(unique) // [1,12,2,22,3,4,5,50,511,6,7,8]
console.log(nonunique) // [1,12,2,22,3,4,5,50,511,6,7,8]
using underscore.js
function hasDuplicate(arr){
return (arr.length != _.uniq(arr).length);
}
The simplest and quickest way is to use the Set object:
const numbers = [1, 2, 3, 2, 4, 5, 5, 6];
const set = new Set(numbers);
const duplicates = numbers.filter(item => {
if (set.has(item)) {
set.delete(item);
return false;
} else {
return true;
}
});
// OR more concisely
const duplicates = numbers.filter(item => !set.delete(item));
console.log(duplicates);
// [ 2, 5 ]
This is my proposal (ES6):
let a = [1, 2, 3, 4, 2, 2, 4, 1, 5, 6]
let b = [...new Set(a.sort().filter((o, i) => o !== undefined && a[i + 1] !== undefined && o === a[i + 1]))]
// b is now [1, 2, 4]
Here's the simplest solution I could think of:
const arr = [-1, 2, 2, 2, 0, 0, 0, 500, -1, 'a', 'a', 'a']
const filtered = arr.filter((el, index) => arr.indexOf(el) !== index)
// => filtered = [ 2, 2, 0, 0, -1, 'a', 'a' ]
const duplicates = [...new Set(filtered)]
console.log(duplicates)
// => [ 2, 0, -1, 'a' ]
That's it.
Note:
It works with any numbers including 0, strings and negative numbers e.g. -1 -
Related question: Get all unique values in a JavaScript array (remove duplicates)
The original array arr is preserved (filter returns the new array instead of modifying the original)
The filtered array contains all duplicates; it can also contain more than 1 same value (e.g. our filtered array here is [ 2, 2, 0, 0, -1, 'a', 'a' ])
If you want to get only values that are duplicated (you don't want to have multiple duplicates with the same value) you can use [...new Set(filtered)] (ES6 has an object Set which can store only unique values)
Hope this helps.
Here is mine simple and one line solution.
It searches not unique elements first, then makes found array unique with the use of Set.
So we have array of duplicates in the end.
var array = [1, 2, 2, 3, 3, 4, 5, 6, 2, 3, 7, 8, 5, 22, 1, 2, 511, 12, 50, 22];
console.log([...new Set(
array.filter((value, index, self) => self.indexOf(value) !== index))]
);
Shortest vanilla JS:
[1,1,2,2,2,3].filter((v,i,a) => a.indexOf(v) !== i) // [1, 2, 2]
one liner simple way
var arr = [9,1,2,4,3,4,9]
console.log(arr.filter((ele,indx)=>indx!==arr.indexOf(ele))) //get the duplicates
console.log(arr.filter((ele,indx)=>indx===arr.indexOf(ele))) //remove the duplicates
var a = [324,3,32,5,52,2100,1,20,2,3,3,2,2,2,1,1,1].sort();
a.filter(function(v,i,o){return i&&v!==o[i-1]?v:0;});
or when added to the prototyp.chain of Array
//copy and paste: without error handling
Array.prototype.unique =
function(){return this.sort().filter(function(v,i,o){return i&&v!==o[i-1]?v:0;});}
See here: https://gist.github.com/1305056
Fast and elegant way using es6 object destructuring and reduce
It runs in O(n) (1 iteration over the array) and doesn't repeat values that appear more than 2 times
const arr = ['hi', 'hi', 'hi', 'bye', 'bye', 'asd']
const {
dup
} = arr.reduce(
(acc, curr) => {
acc.items[curr] = acc.items[curr] ? acc.items[curr] += 1 : 1
if (acc.items[curr] === 2) acc.dup.push(curr)
return acc
}, {
items: {},
dup: []
},
)
console.log(dup)
// ['hi', 'bye']
You can use filter method and indexOf() to get all the duplicate values
function duplicate(arr) {
return duplicateArray = arr.filter((item, index) => arr.indexOf(item) !== index)
}
arr.indexOf(item) will always return the first index at which a given element can be
found
ES5 only (i.e., it needs a filter() polyfill for IE8 and below):
var arrayToFilter = [ 4, 5, 5, 5, 2, 1, 3, 1, 1, 2, 1, 3 ];
arrayToFilter.
sort().
filter( function(me,i,arr){
return (i===0) || ( me !== arr[i-1] );
});
Here is a very light and easy way:
var codes = dc_1.split(',');
var i = codes.length;
while (i--) {
if (codes.indexOf(codes[i]) != i) {
codes.splice(i,1);
}
}
ES6 offers the Set data structure which is basically an array that doesn't accept duplicates.
With the Set data structure, there's a very easy way to find duplicates in an array (using only one loop).
Here's my code
function findDuplicate(arr) {
var set = new Set();
var duplicates = new Set();
for (let i = 0; i< arr.length; i++) {
var size = set.size;
set.add(arr[i]);
if (set.size === size) {
duplicates.add(arr[i]);
}
}
return duplicates;
}
With ES6 (or using Babel or Typescipt) you can simply do:
var duplicates = myArray.filter(i => myArray.filter(ii => ii === i).length > 1);
https://es6console.com/j58euhbt/
Simple code with ES6 syntax (return sorted array of duplicates):
let duplicates = a => {d=[]; a.sort((a,b) => a-b).reduce((a,b)=>{a==b&&!d.includes(a)&&d.push(a); return b}); return d};
How to use:
duplicates([1,2,3,10,10,2,3,3,10]);
I have just figured out a simple way to achieve this using an Array filter
var list = [9, 9, 111, 2, 3, 4, 4, 5, 7];
// Filter 1: to find all duplicates elements
var duplicates = list.filter(function(value,index,self) {
return self.indexOf(value) !== self.lastIndexOf(value) && self.indexOf(value) === index;
});
console.log(duplicates);
This answer might also be helpful, it leverages js reduce operator/method to remove duplicates from array.
const result = [1, 2, 2, 3, 3, 3, 3].reduce((x, y) => x.includes(y) ? x : [...x, y], []);
console.log(result);
Higher ranked answers have a few inherent issues including the use of legacy javascript, incorrect ordering or with only support for 2 duplicated items.
Here's a modern solution which fixes those problems:
const arrayNonUniq = array => {
if (!Array.isArray(array)) {
throw new TypeError("An array must be provided!")
}
return array.filter((value, index) => array.indexOf(value) === index && array.lastIndexOf(value) !== index)
}
arrayNonUniq([1, 1, 2, 3, 3])
//=> [1, 3]
arrayNonUniq(["foo", "foo", "bar", "foo"])
//=> ['foo']
You can also use the npm package array-non-uniq.
The following function (a variation of the eliminateDuplicates function already mentioned) seems to do the trick, returning test2,1,7,5 for the input ["test", "test2", "test2", 1, 1, 1, 2, 3, 4, 5, 6, 7, 7, 10, 22, 43, 1, 5, 8]
Note that the problem is stranger in JavaScript than in most other languages, because a JavaScript array can hold just about anything. Note that solutions that use sorting might need to provide an appropriate sorting function--I haven't tried that route yet.
This particular implementation works for (at least) strings and numbers.
function findDuplicates(arr) {
var i,
len=arr.length,
out=[],
obj={};
for (i=0;i<len;i++) {
if (obj[arr[i]] != null) {
if (!obj[arr[i]]) {
out.push(arr[i]);
obj[arr[i]] = 1;
}
} else {
obj[arr[i]] = 0;
}
}
return out;
}
var arr = [2, 1, 2, 2, 4, 4, 2, 5];
function returnDuplicates(arr) {
return arr.reduce(function(dupes, val, i) {
if (arr.indexOf(val) !== i && dupes.indexOf(val) === -1) {
dupes.push(val);
}
return dupes;
}, []);
}
alert(returnDuplicates(arr));
This function avoids the sorting step and uses the reduce() method to push duplicates to a new array if it doesn't already exist in it.
Is there a javascript equivalent of Python's zip function? That is, given multiple arrays of equal lengths create an array of pairs.
For instance, if I have three arrays that look like this:
var array1 = [1, 2, 3];
var array2 = ['a','b','c'];
var array3 = [4, 5, 6];
The output array should be:
var outputArray = [[1,'a',4], [2,'b',5], [3,'c',6]]
2016 update:
Here's a snazzier Ecmascript 6 version:
zip= rows=>rows[0].map((_,c)=>rows.map(row=>row[c]))
Illustration equiv. to Python{zip(*args)}:
> zip([['row0col0', 'row0col1', 'row0col2'],
['row1col0', 'row1col1', 'row1col2']]);
[["row0col0","row1col0"],
["row0col1","row1col1"],
["row0col2","row1col2"]]
(and FizzyTea points out that ES6 has variadic argument syntax, so the following function definition will act like python, but see below for disclaimer... this will not be its own inverse so zip(zip(x)) will not equal x; though as Matt Kramer points out zip(...zip(...x))==x (like in regular python zip(*zip(*x))==x))
Alternative definition equiv. to Python{zip}:
> zip = (...rows) => [...rows[0]].map((_,c) => rows.map(row => row[c]))
> zip( ['row0col0', 'row0col1', 'row0col2'] ,
['row1col0', 'row1col1', 'row1col2'] );
// note zip(row0,row1), not zip(matrix)
same answer as above
(Do note that the ... syntax may have performance issues at this time, and possibly in the future, so if you use the second answer with variadic arguments, you may want to perf test it. That said it's been quite a while since it's been in the standard.)
Make sure to note the addendum if you wish to use this on strings (perhaps there's a better way to do it now with es6 iterables).
Here's a oneliner:
function zip(arrays) {
return arrays[0].map(function(_,i){
return arrays.map(function(array){return array[i]})
});
}
// > zip([[1,2],[11,22],[111,222]])
// [[1,11,111],[2,22,222]]]
// If you believe the following is a valid return value:
// > zip([])
// []
// then you can special-case it, or just do
// return arrays.length==0 ? [] : arrays[0].map(...)
The above assumes that the arrays are of equal size, as they should be. It also assumes you pass in a single list of lists argument, unlike Python's version where the argument list is variadic. If you want all of these "features", see below. It takes just about 2 extra lines of code.
The following will mimic Python's zip behavior on edge cases where the arrays are not of equal size, silently pretending the longer parts of arrays don't exist:
function zip() {
var args = [].slice.call(arguments);
var shortest = args.length==0 ? [] : args.reduce(function(a,b){
return a.length<b.length ? a : b
});
return shortest.map(function(_,i){
return args.map(function(array){return array[i]})
});
}
// > zip([1,2],[11,22],[111,222,333])
// [[1,11,111],[2,22,222]]]
// > zip()
// []
This will mimic Python's itertools.zip_longest behavior, inserting undefined where arrays are not defined:
function zip() {
var args = [].slice.call(arguments);
var longest = args.reduce(function(a,b){
return a.length>b.length ? a : b
}, []);
return longest.map(function(_,i){
return args.map(function(array){return array[i]})
});
}
// > zip([1,2],[11,22],[111,222,333])
// [[1,11,111],[2,22,222],[null,null,333]]
// > zip()
// []
If you use these last two version (variadic aka. multiple-argument versions), then zip is no longer its own inverse. To mimic the zip(*[...]) idiom from Python, you will need to do zip.apply(this, [...]) when you want to invert the zip function or if you want to similarly have a variable number of lists as input.
addendum:
To make this handle any iterable (e.g. in Python you can use zip on strings, ranges, map objects, etc.), you could define the following:
function iterView(iterable) {
// returns an array equivalent to the iterable
}
However if you write zip in the following way, even that won't be necessary:
function zip(arrays) {
return Array.apply(null,Array(arrays[0].length)).map(function(_,i){
return arrays.map(function(array){return array[i]})
});
}
Demo:
> JSON.stringify( zip(['abcde',[1,2,3,4,5]]) )
[["a",1],["b",2],["c",3],["d",4],["e",5]]
(Or you could use a range(...) Python-style function if you've written one already. Eventually you will be able to use ECMAScript array comprehensions or generators.)
Check out the library Underscore.
Underscore provides over 100 functions that support both your favorite workaday functional helpers: map, filter, invoke β as well as more specialized goodies: function binding, javascript templating, creating quick indexes, deep equality testing, and so on.
β Say the people who made it
I recently started using it specifically for the zip() function and it has left a great first impression. I am using jQuery and CoffeeScript, and it just goes perfectly with them. Underscore picks up right where they leave off and so far it hasn't let me down. Oh by the way, it's only 3kb minified.
Check it out:
_.zip(['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]);
// returns [["moe", 30, true], ["larry", 40, false], ["curly", 50, false]]
Modern ES6 example with a generator:
function *zip (...iterables){
let iterators = iterables.map(i => i[Symbol.iterator]() )
while (true) {
let results = iterators.map(iter => iter.next() )
if (results.some(res => res.done) ) return
else yield results.map(res => res.value )
}
}
First, we get a list of iterables as iterators. This usually happens transparently, but here we do it explicitly, as we yield step-by-step until one of them is exhausted. We check if any of results (using the .some() method) in the given array is exhausted, and if so, we break the while loop.
In addition to ninjagecko's excellent and comprehensive answer, all it takes to zip two JS-arrays into a "tuple-mimic" is:
//Arrays: aIn, aOut
Array.prototype.map.call( aIn, function(e,i){return [e, aOut[i]];})
Explanation:
Since Javascript doesn't have a tuples type, functions for tuples, lists and sets wasn't a high priority in the language specification.
Otherwise, similar behavior is accessible in a straightforward manner via Array map in JS >1.6. (map is actually often implemented by JS engine makers in many >JS 1.4 engines, despite not specified).
The major difference to Python's zip, izip,... results from map's functional style, since map requires a function-argument. Additionally it is a function of the Array-instance. One may use Array.prototype.map instead, if an extra declaration for the input is an issue.
Example:
_tarrin = [0..constructor, function(){}, false, undefined, '', 100, 123.324,
2343243243242343242354365476453654625345345, 'sdf23423dsfsdf',
'sdf2324.234dfs','234,234fsf','100,100','100.100']
_parseInt = function(i){return parseInt(i);}
_tarrout = _tarrin.map(_parseInt)
_tarrin.map(function(e,i,a){return [e, _tarrout[i]]})
Result:
//'('+_tarrin.map(function(e,i,a){return [e, _tarrout[i]]}).join('),\n(')+')'
>>
(function Number() { [native code] },NaN),
(function (){},NaN),
(false,NaN),
(,NaN),
(,NaN),
(100,100),
(123.324,123),
(2.3432432432423434e+42,2),
(sdf23423dsfsdf,NaN),
(sdf2324.234dfs,NaN),
(234,234fsf,234),
(100,100,100),
(100.100,100)
Related Performance:
Using map over for-loops:
See: What is the most efficient way of merging [1,2] and [7,8] into [[1,7], [2,8]]
Note: the base types such as false and undefined do not posess a prototypal object-hierarchy and thus do not expose a toString function. Hence these are shown as empty in the output.
As parseInt's second argument is the base/number radix, to which to convert the number to, and since map passes the index as the second argument to its argument-function, a wrapper function is used.
Along other Python-like functions, pythonic offers a zip function, with the extra benefit of returning a lazy evaluated Iterator, similar to the behaviour of its Python counterpart:
import {zip, zipLongest} from 'pythonic';
const arr1 = ['a', 'b'];
const arr2 = ['c', 'd', 'e'];
for (const [first, second] of zip(arr1, arr2))
console.log(`first: ${first}, second: ${second}`);
// first: a, second: c
// first: b, second: d
for (const [first, second] of zipLongest(arr1, arr2))
console.log(`first: ${first}, second: ${second}`);
// first: a, second: c
// first: b, second: d
// first: undefined, second: e
// unzip
const [arrayFirst, arraySecond] = [...zip(...zip(arr1, arr2))];
Disclosure I'm author and maintainer of Pythonic
Python has two function to zip sequences: zip and itertools.zip_longest. An implementation in Javascript for the same functionality is this:
Implementation of Python`s zip on JS/ES6
const zip = (...arrays) => {
const length = Math.min(...arrays.map(arr => arr.length));
return Array.from({ length }, (value, index) => arrays.map((array => array[index])));
};
Results in:
console.log(zip(
[1, 2, 3, 'a'],
[667, false, -378, '337'],
[111],
[11, 221]
));
[ [ 1, 667, 111, 11 ] ]
console.log(zip(
[1, 2, 3, 'a'],
[667, false, -378, '337'],
[111, 212, 323, 433, '1111']
));
[ [ 1, 667, 111 ], [ 2, false, 212 ], [ 3, -378, 323 ], [ 'a',
'337', 433 ] ]
console.log(zip(
[1, 2, 3, 'a'],
[667, false, -378, '337'],
[111],
[]
));
[]
Implementation of Python`s zip_longest on JS/ES6
(https://docs.python.org/3.5/library/itertools.html?highlight=zip_longest#itertools.zip_longest)
const zipLongest = (placeholder = undefined, ...arrays) => {
const length = Math.max(...arrays.map(arr => arr.length));
return Array.from(
{ length }, (value, index) => arrays.map(
array => array.length - 1 >= index ? array[index] : placeholder
)
);
};
Results:
console.log(zipLongest(
undefined,
[1, 2, 3, 'a'],
[667, false, -378, '337'],
[111],
[]
));
[ [ 1, 667, 111, undefined ], [ 2, false, undefined, undefined ],
[ 3, -378, undefined, undefined ], [ 'a', '337', undefined,
undefined ] ]
console.log(zipLongest(
null,
[1, 2, 3, 'a'],
[667, false, -378, '337'],
[111],
[]
));
[ [ 1, 667, 111, null ], [ 2, false, null, null ], [ 3, -378,
null, null ], [ 'a', '337', null, null ] ]
console.log(zipLongest(
'Is None',
[1, 2, 3, 'a'],
[667, false, -378, '337'],
[111],
[]
));
[ [ 1, 667, 111, 'Is None' ], [ 2, false, 'Is None', 'Is None' ],
[ 3, -378, 'Is None', 'Is None' ], [ 'a', '337', 'Is None', 'Is
None' ] ]
You can make utility function by using ES6.
console.json = obj => console.log(JSON.stringify(obj));
const zip = (arr, ...arrs) =>
arr.map((val, i) => arrs.reduce((a, arr) => [...a, arr[i]], [val]));
// Example
const array1 = [1, 2, 3];
const array2 = ['a','b','c'];
const array3 = [4, 5, 6];
console.json(zip(array1, array2)); // [[1,"a"],[2,"b"],[3,"c"]]
console.json(zip(array1, array2, array3)); // [[1,"a",4],[2,"b",5],[3,"c",6]]
However, in above solution length of the first array defines the length of the output array.
Here is the solution in which you have more control over it. It's bit complex but worth it.
function _zip(func, args) {
const iterators = args.map(arr => arr[Symbol.iterator]());
let iterateInstances = iterators.map((i) => i.next());
ret = []
while(iterateInstances[func](it => !it.done)) {
ret.push(iterateInstances.map(it => it.value));
iterateInstances = iterators.map((i) => i.next());
}
return ret;
}
const array1 = [1, 2, 3];
const array2 = ['a','b','c'];
const array3 = [4, 5, 6];
const zipShort = (...args) => _zip('every', args);
const zipLong = (...args) => _zip('some', args);
console.log(zipShort(array1, array2, array3)) // [[1, 'a', 4], [2, 'b', 5], [3, 'c', 6]]
console.log(zipLong([1,2,3], [4,5,6, 7]))
// [
// [ 1, 4 ],
// [ 2, 5 ],
// [ 3, 6 ],
// [ undefined, 7 ]]
1. Npm Module: zip-array
I found an npm module that can be used as a javascript version of python zip:
zip-array - A javascript equivalent of Python's zip function. Merges together the values of each of the arrays.
https://www.npmjs.com/package/zip-array
2. tf.data.zip() in Tensorflow.js
Another alternate choice is for Tensorflow.js users: if you need a zip function in python to work with tensorflow datasets in Javascript, you can use tf.data.zip() in Tensorflow.js.
tf.data.zip() in Tensorflow.js documented at here
Original answer (see update below)
I modified flm's nifty answer to take an arbitrary number of arrays:
function* zip(arrays, i = 0) {
while (i<Math.min(...arrays.map(({length})=>length))) {
yield arrays.map((arr, j) => arr[j < arrays.length - 1 ? i : i++])
}
}
Updated answer
As pointed out by Tom Pohl this function can't deal with arrays with falsy values in. Here is an updated/improved version that can deal with any types and also unequal length arrays:
function* zip(arrays, i = 0) {
while (i<Math.min(...arrays.map(arr=>arr.length))) {
yield arrays.map((arr, j) => arr[j < arrays.length - 1 ? i : i++])
}
}
const arr1 = [false,0,1,2]
const arr2 = [100,null,99,98,97]
const arr3 = [7,8,undefined,"monkey","banana"]
console.log(...zip([arr1,arr2,arr3]))
Not built-in to Javascript itself. Some of the common Javascript frameworks (such as Prototype) provide an implementation, or you can write your own.
Like #Brandon, I recommend Underscore's zip function. However, it acts like zip_longest, appending undefined values as needed to return something the length of the longest input.
I used the mixin method to extend underscore with a zipShortest, which acts like Python's zip, based off of the library's own source for zip.
You can add the following to your common JS code and then call it as if it were part of underscore: _.zipShortest([1,2,3], ['a']) returns [[1, 'a']], for example.
// Underscore library addition - zip like python does, dominated by the shortest list
// The default injects undefineds to match the length of the longest list.
_.mixin({
zipShortest : function() {
var args = Array.Prototype.slice.call(arguments);
var length = _.min(_.pluck(args, 'length')); // changed max to min
var results = new Array(length);
for (var i = 0; i < length; i++) {
results[i] = _.pluck(args, "" + i);
}
return results;
}});
A variation of the lazy generator solution:
function* iter(it) {
yield* it;
}
function* zip(...its) {
its = its.map(iter);
while (true) {
let rs = its.map(it => it.next());
if (rs.some(r => r.done))
return;
yield rs.map(r => r.value);
}
}
for (let r of zip([1,2,3], [4,5,6,7], [8,9,0,11,22]))
console.log(r.join())
// the only change for "longest" is some -> every
function* zipLongest(...its) {
its = its.map(iter);
while (true) {
let rs = its.map(it => it.next());
if (rs.every(r => r.done))
return;
yield rs.map(r => r.value);
}
}
for (let r of zipLongest([1,2,3], [4,5,6,7], [8,9,0,11,22]))
console.log(r.join())
And this is the python's classic "n-group" idiom zip(*[iter(a)]*n):
triples = [...zip(...Array(3).fill(iter(a)))]
ES2020 shortest variant:
function * zip(arr1, arr2, i = 0) {
while(arr1[i] || arr2[i]) yield [arr1[i], arr2[i++]].filter(x => !!x);
}
[ ...zip(arr1, arr2) ] // result
You could reduce the array of arrays and map new array by taking the result of the index of the inner array.
var array1 = [1, 2, 3],
array2 = ['a','b','c'],
array3 = [4, 5, 6],
array = [array1, array2, array3],
transposed = array.reduce((r, a) => a.map((v, i) => (r[i] || []).concat(v)), []);
console.log(transposed);
Fun with spread.
const
transpose = (r, a) => a.map((v, i) => [...(r[i] || []), v]),
array1 = [1, 2, 3],
array2 = ['a','b','c'],
array3 = [4, 5, 6],
transposed = [array1, array2, array3].reduce(transpose, []);
console.log(transposed);
I took a run at this in pure JS wondering how the plugins posted above got the job done. Here's my result. I'll preface this by saying that I have no idea how stable this will be in IE and the like. It's just a quick mockup.
init();
function init() {
var one = [0, 1, 2, 3];
var two = [4, 5, 6, 7];
var three = [8, 9, 10, 11, 12];
var four = zip(one, two, one);
//returns array
//four = zip(one, two, three);
//returns false since three.length !== two.length
console.log(four);
}
function zip() {
for (var i = 0; i < arguments.length; i++) {
if (!arguments[i].length || !arguments.toString()) {
return false;
}
if (i >= 1) {
if (arguments[i].length !== arguments[i - 1].length) {
return false;
}
}
}
var zipped = [];
for (var j = 0; j < arguments[0].length; j++) {
var toBeZipped = [];
for (var k = 0; k < arguments.length; k++) {
toBeZipped.push(arguments[k][j]);
}
zipped.push(toBeZipped);
}
return zipped;
}
It's not bulletproof, but it's still interesting.
A generator approach to pythons zip function.
function* zip(...arrs){
for(let i = 0; i < arrs[0].length; i++){
a = arrs.map(e=>e[i])
if(a.indexOf(undefined) == -1 ){yield a }else{return undefined;}
}
}
// use as multiple iterators
for( let [a,b,c] of zip([1, 2, 3, 4], ['a', 'b', 'c', 'd'], ['hi', 'hello', 'howdy', 'how are you']) )
console.log(a,b,c)
// creating new array with the combined arrays
let outputArr = []
for( let arr of zip([1, 2, 3, 4], ['a', 'b', 'c', 'd'], ['hi', 'hello', 'howdy', 'how are you']) )
outputArr.push(arr)
I have created a simple function to do so with a option to provide an zipper function
function zip(zipper, ...arrays) {
if (zipper instanceof Array) {
arrays.unshift(zipper)
zipper = (...elements) => elements
}
const length = Math.min(...arrays.map(array => array.length))
const zipped = []
for (let i = 0; i < length; i++) {
zipped.push(zipper(...arrays.map(array => array[i])))
}
return zipped
}
https://gist.github.com/AmrIKhudair/4b740149c29c492859e00f451832975b
I'm not a javascript guy but I feel like many of these answers are trying to find the cutest and most clever solution using Array.map which is fine, but for someone like me that doesn't use javascript every day here are some alternatives that might possibly be a bit more readable.
Maybe a way to avoid some cute and clever code would be:
function zip(a,b){
// pre-allocate an array to hold the results
rval=Array(Math.max(a.length, b.length));
for(i=0; i<rval.length; i++){
rval[i]=[a[i],b[i]]
}
return rval
}
If you like generators:
function* _zip(a,b){
len = Math.max(a.length, b.length) // handle different sized arrays
for(i=0; i<len; i++) { yield [a[i],b[i]] }
}
Or if you really want to use Array.map:
function map(a,b){
x = a.length > b.length ? a : b // call map on the biggest array
return x.map((_,i)=>[a[i],b[i]])
}
As I said, I'm not an everyday javascript guy so, these aren't going to be the most elegant solutions but they are readable to me.
Below is a fast and efficient way of doing this, using iter-ops library, operator zip:
const {pipe, zip} = require('iter-ops');
const i = pipe(array1, zip(array2, array3));
console.log(...i); //=> [ 1, 'a', 4 ] [ 2, 'b', 5 ] [ 3, 'c', 6 ]
The library processes all inputs as iterables, so they are iterated over just once. And it can handle, in the same way, all types of iterable objects - Iterable, AsyncIterable, Iterator, AsyncIterator.
P.S. I'm the author of iter-ops.
The Mochikit library provides this and many other Python-like functions. developer of Mochikit is also a Python fan, so it has the general style of Python, and also the wraps the async calls in a twisted-like framework.
There is no equivalent function. If you have only a few arrays you should use a for loop to get an index and then use the index to access the arrays:
var array1 = [1, 2, 3];
var array2 = ['a','b','c'];
for (let i = 0; i < Math.min(array1.length, array2.length); i++) {
doStuff(array1[i], array2[i]);
}
You can have an inner loop over the arrays if you have more.
Here is my solution
let zip = (a, b) => (a.length < b.length
? a.map((e, i) => [e, b[i]])
: b.map((e, i) => [a[i], e]))
This shaves a line off Ddi's iterator-based answer:
function* zip(...toZip) {
const iterators = toZip.map((arg) => arg[Symbol.iterator]());
const next = () => toZip = iterators.map((iter) => iter.next());
while (next().every((item) => !item.done)) {
yield toZip.map((item) => item.value);
}
}
If you are fine with ES6:
const zip = (arr,...arrs) =>(
arr.map(
(v,i) => arrs.reduce((a,arr)=>[...a, arr[i]], [v])))