Move item in array to last position - javascript

I have an array of objects. I want to move a selected object to the last position in the array. How do I do this in javascript or jquery?
Here is some code I have:
var sortedProductRow = this.product_row;
for (var s in sortedProductRow) {
if (sortedProductRow[s]["parent_product_type"] != "")
// Move this object to last position in the array
}
I'm looping through this with a for loop, and I want the output to be ordered so that all objects that does not have a "parent_product_type" value comes first, then those with a value.

to move an element (of which you know the index) to the end of an array, do this:
array.push(array.splice(index, 1)[0]);
If you don't have the index, and only the element, then do this:
array.push(array.splice(array.indexOf(element), 1)[0]);
Example:
var arr = [1, 2, 6, 3, 4, 5];
arr.push(arr.splice(arr.indexOf(6), 1)[0]);
console.log(arr); // [1, 2, 3, 4, 5, 6]
NOTE:
this only works with Arrays (created with the [ ... ] syntax or
Array()) not with Objects (created with the { ... } syntax or
Object())

Moving the first element of an array to the end of the same array
var a = [5,1,2,3,4];
a.push(a.shift());
console.log(a); // [1,2,3,4,5]
or this way
var a = [5,1,2,3,4];
var b = a.shift();
a[a.length] = b;
console.log(a); // [1,2,3,4,5]
Moving any element of an array to any position in the same array
// move element '5' (index = 2) to the end (index = 4)
var a = [1, 2, 5, 4, 3];
a.splice(4,0,a.splice(2,1)[0]);
console.log(a); // [1, 2, 4, 3, 5]
or it could be converted to a prototype as well, like this where x represents the current position of element while y represents the new position in array
var a = [1, 2, 5, 4, 3];
Array.prototype.move = function(x, y){
this.splice(y, 0, this.splice(x, 1)[0]);
return this;
};
a.move(2,4);
console.log(a); // ["1", "2", "4", "3", "5"]
Answer to the #jkalandarov comment
function moveToTheEnd(arr, word){
arr.map((elem, index) => {
if(elem.toLowerCase() === word.toLowerCase()){
arr.splice(index, 1);
arr.push(elem);
}
})
return arr;
}
console.log(moveToTheEnd(["Banana", "Orange", "Apple", "Mango", "Lemon"],"Orange"));

This is more clean, without using the array index of [0]
const colors = ['white', 'black', 'red', 'blue', 'green'];
// will push the blue to the end of the array
colors.push(colors.splice(colors.indexOf('blue'), 1).pop());
console.debug(colors);
// ["white", "black", "red", "green", "blue"]

Using an anonymous function you can pass in the array and the value to filter by.
let concatToEnd = function (arr, val) {
return arr.filter(function(x) {
return x !== val; // filter items not equal to value
}).concat(arr.filter(function(x) { // concatonate to filtered array
return x === val; // filter items equal to value
})
);
}
// invoke
concatToEnd(array, 'parent_product_type');
You could probably shorten this further:
let concatToEnd = (arr,val) => arr.filter(x => x !== val).concat(arr.filter(x => x === val))
This function filters the items which do not equal the value passed in, then concatenates the result (to the end of the filtered array) of another filter function which filters out the items which do equal the value you've passed in.
This function essentially separates the array into 2 filtered parts and then concatenates them back together
This hasn't been tested for your use-case, but I've used something similar to move all numbers of an array to the end of the index.

Immutable way:
const changedArr = [...prevArr.filter(a => a !== element), element]

Move any element to last position - for lodash users:
const array = ['A', 'B', 'C', 'D'] // output: A, B, C, D
// finds index of value 'B' and removes it
_.pull(array , 'B') // output: A, C, D
// adds value of 'B' to last position
_.concat(array , 'B') // output: A, C, D, B

You can move any number of items by splicing them, then spreading them into a push.
const numberOfItems = 3;
let items = [1,2,3,4,5,6,7,8,9];
items.push(...items.splice(0, itemsToMove))

Moving all items equal so something to the end can also be done by concat.
const myArray = [1, 0, 3, 5, 0, 'a', 3, 's']
const moveZerosToEnd = (arr) => {
return arr.filter(item => item !== 0).concat(arr.filter(item => item === 0))
}
console.log(myArray) // [1, 0, 3, 5, 0, 'a', 3, 's']
console.log(moveZerosToEnd(myArray)) // [1, 3, 5, 'a', 3, 's', 0, 0]

Related

Is there any way to modify criteria of what values to allow in an Array?

I have an array of values. I want to make a second array based on the first one with stricter criteria. For example, what I want specifically is:
arrayOne[1,1,1,1,1,2,2,2,3,3,3,3,4,4,4,4,4,5,5,5]
How would I make it so in my new array, only the values that show up 5 times are a part of the array and only show up once. Example: arrayTwo [1,4]
I'm fairly new to JavaScript and have been given an opportunity to code a decision making system for one of my business courses instead of doing the final exam. Any help you can give would be much appreciated. Thank You.
You could use a hash table, which counts each found element and then use the count for filtering and get only the fifth element as result set in a single loop.
var array = [1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5],
count = Object.create(null),
result = array.filter(v => (count[v] = (count[v] || 0) + 1) === 5);
console.log(result);
I commented the code with the steps I took:
const arrayOne = [1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5];
function method(arr, minimum) {
//Create an object containing the amount each number occurs
const occurrences = arr.reduce((o, n) => {
//If number is already in the object add 1
if (o[n]) o[n] = o[n] + 1;
//Else set its occurence to 1
else o[n] = 1;
//Return the object for the next iteration
return o;
}, {});
//Deduplicate the array be creating a Set(every elements can only occur once) and spread it back into an array
const deduplicate = [...new Set(arr)];
//Filter array to only contain elements which have the minimum of occurences
const filtered = deduplicate.filter(n => occurrences[n] >= minimum);
return filtered;
}
console.log(method(arrayOne, 5));
You can use a Map for this.
let arrayOne = [1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5];
let counterMap = new Map();
arrayOne.forEach(value => {
let valueStr = value.toString();
counterMap.set(valueStr, counterMap.has(valueStr) ? counterMap.get(valueStr) + 1 : 1);
});
let arrayTwo = [];
counterMap.forEach((value, key, map) => {
if(value >= 5) {
arrayTwo.push(key);
}
});
console.log(arrayTwo);
Not the most elegant answer, but I assume you're looking just to find all values that appear at least 5 times.
const arrayOne = [1,1,1,1,1,2,2,2,3,3,3,3,4,4,4,4,4,5,5,5]
const arrayTwo = Object.entries(arrayOne.reduce((obj, num) => {
if(!obj[num]){
obj[num] = 1
} else {
obj[num] = obj[num] + 1
}
return obj
}, {})).filter(([key, value]) => {
return value >= 5
}).map((item) => {
return parseInt(item[0])
})
console.log(arrayTwo)
const a = [1,1,1,1,1,2,2,2,3,3,3,3,4,4,4,4,4,5,5,5,5,5,5,5,5,5];
Define a function that will take an array and numOfOccurrences
const filterByOcur = (arr, numOfOccurrences) => {
// create an object to act as a counter this will let us
// iterate over the array only once
const counter = {};
const res = new Set();
for (let num of arr) {
// if it's the first time we see the num set counter.num to 1;
if (!counter[num]) counter[num] = 1;
// if counter.num is greater or equal to numOfOccurrences
// and we don't have the num in the set add it to the set
else if (++counter[num] >= numOfOccurrences && !res.has(num)) res.add(num);
}
// spread the Set into an array
return [...res];
};
console.log(
filterByOcur(a, 5)
);
There is number of ways of doing this, I will try to explain this step by step:
Array declaration
const a = [1,1,1,1,1,2,2,2,3,3,3,3,4,4,4,4,4,5,5,5]
Method to count elements in an array, we are using reducer function that as a first argument takes object where key is our value from array and has a incremental number as a value. Remeber to start reducer with empty object
const counted = a.reduce((counter, value) => {
if (counter[value]) counter[value]++
else counter[value] = 1
return counter
}, {})
Make your array unique with Set constructor
const uniq = Array.from(new Set(a))
Fire filter functions on the uniq array with a help of counted array, look how we access it:
const onlyOne = uniq.filter(val => counted[val] === 1)
const onlyFive = uniq.filter(val => counted[val] === 5)
Merge all filtered arrays into one
const final = [].concat(onlyOne, onlyFive)

Sort an object according to an array with underscore

I am trying to sort an object comparing with an array. So the loop will look for specific values on the array, until it finds one, and put those 3 elements at the beginning and the rest at the end.
I am unsure what is the best way to do this any ideas?
It is something like that:
var arr = [1, 3, 2,4,5,6, 2];
var arrSimilar = [1,2,5]
var testSortBy = _.sortBy(arr, function(arrSimilar){
// [1,2,5,3,4,6,2]
});
console.log(testSortBy); // [1,2,5,3,4,6,2]
You could use sorting with map and take the index of the value of similar array as priority sorting and then take the index of all other values as order.
Important is to delete a used value of the similar array, because it is now in use and has no meaning for further similar values. That means, same values are sorted to their original relative index.
var array = [1, 3, 2, 4, 5, 6, 2],
similar = [1, 2, 5],
result = array
.map(function (a, i) {
var priority = similar.indexOf(a);
delete similar[priority]; // delete value, but keep the index of other items
return { index: i, priority: (priority + 1) || Infinity };
})
.sort(function (a, b) {
return a.priority - b.priority || a.index - b.index;
})
.map(function (o) {
return array[o.index];
});
console.log(result); // [1, 2, 5, 3, 4, 6, 2]
You can do that in the following way
Suppose A[] is the original array and B is the priority Array
The answer would be (B intersection A) concat (A-B)
var arr = [1, 3, 2,4,5,6];
var arrSimilar = [1,2,5];
let bInterA = arrSimilar.filter((e) => arr.indexOf(e) != -1);
let aDiffb = arr.filter((e) => arrSimilar.indexOf(e) == -1);
console.log(bInterA.concat(aDiffb));

Can i sort nested array using nested sort()?

This should be the input array
var a = [2,1,3,4,1,[4,6,2,4],2,4,1];
For the output i have two cases :- (index of internal array is not changing)
a = [1,1,2,3,4,[2,4,4,6],1,2,4]
and
a = [1,1,1,2,2,[2,4,4,6],3,4,4]
This is what i am trying to use :-
a.sort(function(a,b){
if(b instanceof Array){
b.sort();
}
})
Array.sort() is not built to handle partial Arrays, what you would need in your case, but we can work around this problem by pre-processing the data (wrapping it with additional information), then sorting and at the end, extracting the original values:
case 1: sorting the parts between the Arrays
[2,1,3,4,1,[4,6,2,4],2,4,1] -> [1,1,2,3,4,[2,4,4,6],1,2,4]
function sort1(arr){
//I add an artificial "property" of to the values, to "describe" the groups, and to be able to sort by
//each Array is it's own group (so they stay in order), and the values in between share the same group
var group = 0,
isArray = false;
//an intermediate Array holding all the information (in order) to either apply it to the current Array, or to return (map) it as a new Array
var intermediate = arr.map(function(v,i){
//last value was an Array, this is the first value after an Array, start a new group
if(isArray) ++group;
if(isArray = Array.isArray(v)){ //update isArray
v = sort1(v); //recursive sorting
++group; //the last group just ended here
}
//return a composition, that contains all the data I need to sort by
return {
group: group,
value: v
}
}).sort(function(a, b){
//forst sort by group, and (only) if two values share the same group, sort by the original value
return a.group - b.group || a.value - b.value
});
//apply data to current Array
intermediate.forEach(function(obj, i){ arr[i] = obj.value });
return arr;
//return new Array
//return intermediate.map(function(obj){ return obj.value });
}
case 2: treating an Array like it's first value
[2,1,3,4,1,[4,6,2,4],2,4,1] -> [1,1,1,2,2,[2,4,4,6],3,4,4]
function sort2(arr){
//an utility to fetch the first non-array value recursively
function _value(v){
while(Array.isArray(v)) v = v[0];
return v;
}
var intermediate = arr.map(function(v, i){
if(Array.isArray(v)) v = sort2(v);
return {
index: i,
value: v,
sortingValue: _value(v)
}
}).sort(function(a, b){
return a.sortingValue - b.sortingValue || a.index - b.index;
});
//apply data to current Array
intermediate.forEach(function(obj, i){ arr[i] = obj.value });
return arr;
//return new Array
//return intermediate.map(function(obj){ return obj.value });
}
This is the perfect solution, use nested function invoke to sort array.
Firstly , store all the array position and sub array.
Secondly, extract numbers into new array,
Finally insert sorted array into same position as before.
var a = [2,1,3,4,1,[4,6,[4,5,[7,3,2,1,6],1,2],2,4],2,4,1];
function nestedSort(arr){
var items = [];
var numArr = [];
for ( key in arr){
if (arr[key] instanceof Array)
{
items.push({index:key,array:arr[key]});
}else{
numArr.push(arr[key]);
}
}
numArr.sort();
for (key in items){
numArr.splice(items[key].index,0,nestedSort(items[key].array));
}
return numArr;
}
console.log(nestedSort(a));
[
1,
1,
1,
2,
2,
[
2,
4,
[
1,
2,
[
1,
2,
3,
6,
7
],
4,
5
],
4,
6
],
3,
4,
4
]
Hope this can solve your problem. :)
You can loop over array and remove all sub arrays and save their index and then sort the new array and again push sorted sub arrays on specific indexes.
Sample
var arr = [2, 1, 3, 4, 1, [4, 6, 2, 4], 2, 4, 1];
var arr1 = [2, 1, 3, 4, 1, [4, 6, 2, 4], 2, 6, 4, [4, 5, 3], 1, 2, 1, 3]
var a = [2,1,3,4,1,[4,6,[4,5,[7,3,2,1,6],1,2],2,4],2,4,1];
function mySort(arr) {
var _list = [];
arr.forEach(function(item, index) {
if (Array.isArray(item)) {
_list.push({
index: index,
value: arr.splice(index, 1).pop()
});
}
});
arr.sort();
_list.forEach(function(item) {
arr.splice(item.index, 0, mySort(item.value))
})
return arr;
}
console.log(mySort(arr.slice()))
console.log(mySort(arr1.slice()))
console.log(mySort(a.slice()))
Edit 1
Inspired from joey-etamity's answer, have made it generic for nested structure.
No, you don't put the sort call in the comparison function. You would recurse through your arrays, bottom to top, and sort them one after the other. In your case you might not even need recursion if it's only one array in another:
a.forEach(function(element) {
if (Array.isArray(element))
element.sort(function compare(a, b) { return a-b; });
})
(I've chosen a simple numerical compare here).
Then you'd sort the outer array:
a.sort(function compare(a, b) {
if (Array.isArray(a)) a = a[0];
if (Array.isArray(b)) b = b[0];
return a - b;
})
(here compare takes the first element of the array to compare by that against the other numbers).
I suggest to splice the array if there is an element an array. Then sort the array and reassemble the array.
This proposal iterates from the back and keeps the array intact while splicing.
function sort(array) {
var i = array.length,
inside = [];
while (i--) {
if (Array.isArray(array[i])) {
inside.unshift({ pos: i, value: sort(array.splice(i, 1)[0]) });
}
}
array.sort(function (a, b) { return a - b; });
inside.forEach(function (a) {
array.splice(a.pos, 0, a.value);
});
return array;
}
var a = [2, 1, 3, 4, 1, [4, 6, 2, 4], 2, 4, 1];
console.log(sort(a));
I think this would be better to use Array.prototype.sort this way:
// var arr = [2, 1, 3, 4, 1, [4, 6, 2, 4], 2, 4, 1];
var arr = [2, 1, 3, 4, 1, [4, 6, 2, 4], 2, 6, 4, [4, 5, 3], 1, 2, 1, 3];
var chunks = chunkate(arr)
console.log(JSON.stringify(chunks));
chunks.forEach(ch => ch.sort(_sort));
var result = chunks.reduce((p, c) => p.concat(c));
console.log(JSON.stringify(result));
function _sort(a, b) {
var isAa = Array.isArray(a),
isAb = Array.isArray(b);
isAb && b.sort(_sort);
return (isAa || isAb) ? 0 : a - b;
}
function chunkate(arr) {
return arr.reduce((a, c) => {
Array.isArray(c) ? a.push(chunkate(c), []) : a[a.length - 1].push(c)
return a;
}, [[]]);
}
How it works?
If items to compare are are array then they shouldn't be replaced so by sending false sort function recognize that there is no need to replace. Otherwise the simple compare is the answer.
Edit
As discussed in comments, it's better to separate values to chunks and then sort each part then join parts again. If nesting depth is only one level you can use default sort (without _sort function) but be aware of array in array used for nested array. So the sort should be changed like this:
chunks.forEach(ch => Array.isArray(ch[0])? ch[0].sort(): ch.sort());

diff 2 arrays where items were simply reordered

Given two arrays arr1 and arr2 that both have the same items, but are sorted differently, how to make a list of least number of item-move operations required to make arr1 match arr2?
The function / algorithm to do this should accept my two arrays as the only arguments, and return an array like this:
[
[1,5],
[3,0],
[7,2]
]
The above array would be interpreted as "Move item at index 1 to index 5, then move item at index 3 to index 0, and finally move item at index 7 to index 2."
By an item-move operation I mean the following:
function arrayMove(array, from, to) {
return array.splice(to, 0, array.splice(from, 1)[0]);
}
When an item is moved from index a to index b, items after index a "slide down" so the item that had index a + 1 now has index a, and when the item is added back at index b, the items that had an index >= b will slide up, so that the item that had index b would now have index b + 1.
Feel free to provide your algorithm in JS or pseudocode, any help appreciated.
This strikes me as related to the edit distance problem. Perhaps you could exploit the Wagner-Fischer algorithm.
Something like this perhaps?
Javascript
// swap two elements in an array by their indexes a and b and
// return an array of the swapped coordinates.
function swap(arr, a, b) {
// assign the value at index a to temp
var temp = arr[a];
// assign the value at index b to index a
arr[a] = arr[b];
// assign the value of temp to the value at index b
arr[b] = temp;
// coordinates of move
return [a, b];
}
// return an array of moved coordinates
function minMoves(arr1, arr2) {
// take a shallow copy of arr2 so that the original is not modified
arr2 = arr2.slice();
// apply a function against an accumulator (moves) for each value of
// the array (arr1) (from left-to-right)
return arr1.reduce(function (moves, item, index) {
// if the values of each array at the index are not the same
if (item !== arr2[index]) {
// swap the current indexed element of arr2 with the value of
// the correct element as indexed in arr1. Add the moved
// coordinates to the beginning of the accumulator
moves.unshift(swap(arr2, index, arr2.lastIndexOf(item)));
}
// return the accumulater for the next iteration
return moves;
}, []);
}
var before = [1, 5, 6, 3, 2, 4, 7, 8, 9, 0],
test = before.slice(),
after = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0],
moves = minMoves(before, after);
console.log('moves: ' + JSON.stringify(moves));
moves.forEach(function(move) {
swap(test, move[0], move[1]);
});
console.log('Should be ordered nicely: ' + JSON.stringify(test));
Output
moves: [[3,5],[2,5],[1,4]]
Should be ordered nicely: [1,2,3,4,5,6,7,8,9,0]
On jsFiddle
This is what I would do, it is not based on any research of algorithms that have been proven optimal.
And here is the code using your arrayMove method instead of swap
Javascript
function arrayMove(array, from, to) {
return array.splice(to, 0, array.splice(from, 1)[0]);
}
// return an array of moved coordinates
function minMoves(arr1, arr2) {
// take a shallow copy of arr2 so that the original is not modified
arr2 = arr2.slice();
// apply a function against an accumulator (moves) for each value of
// the array (arr1) (from left-to-right)
return arr1.reduce(function (moves, item, index) {
var last;
// if the values of each array at the index are not the same
if (item !== arr2[index]) {
// swap the current indexed element of arr2 with the value of
// the correct element as indexed in arr1. Add the moved
// coordinates to the beginning of the accumulator
last = arr2.lastIndexOf(item);
arrayMove(arr2, last, index);
moves.unshift([index, last]);
}
// return the accumulater for the next iteration
return moves;
}, []);
}
var before = [1, 5, 6, 3, 2, 4, 7, 8, 9, 0],
test = before.slice(),
after = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0],
moves = minMoves(before, after);
console.log('moves: ' + JSON.stringify(moves));
moves.forEach(function(move) {
arrayMove(test, move[0], move[1]);
});
console.log('Should be ordered nicely: ' + JSON.stringify(test));
Output
moves: [[3,4],[2,5],[1,4]]
Should be ordered nicely: [1,2,3,4,5,6,7,8,9,0]
On jsFiddle
Finally a jsPerf to compare the two methods.

How to find duplicated values in an Array [duplicate]

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.

Categories