Group same values in an array within an array in JS - javascript

How can I group the same numbers in an array within an array?
I have the following array of numbers:
var arr = [1,1,1,1,2,2,3,3,3,4,5,5,6];
My output should be
[[1,1,1,1],[2,2],[3,3,3],4,[5,5],6]

You could reduce the array and check if the predecessor has the same value and if not take either an array or the value, depending of the next element.
var array = [1, 1, 1, 1, 2, 2, 3, 3, 3, 4, 5, 5, 6],
grouped = array.reduce((r, v, i, a) => {
if (v === a[i - 1]) {
r[r.length - 1].push(v);
} else {
r.push(v === a[i + 1] ? [v] : v);
}
return r;
}, []);
console.log(grouped);

I recently came across this issue. The answers provided work well but I wanted a simpler approach without having to import from lodash or underscore. Here's the tl;dr (too long didn't read):
const groupedObj = arr.reduce(
(prev, current) => ({
...prev,
[current]: [...(prev[current] || []), current],
}),
{}
);
const groupedObjToArr = Object.values(groupedObj);
Explanation
We want to create an object where each unique number is an attribute or key in the object and it's value is an array of all the numbers that are the same. For the provided array:
const arr = [1,1,1,1,2,2,3,3,3,4,5,5,6];
our object should come out to be:
{
1: [1,1,1,1],
2: [2,2],
3: [3,3,3],
4: [4],
5: [5,5],
6: [6]
}
To do that, we will reduce the provided array (docs on .reduce method can be found on MDN by searching array reduce).
arr.reduce((previous, current, idx, array) => {}, {});
Quick Breakdown on Reduce
Reduce is a method on Array that takes two parameters: a callback and an initial value. Reduce provides four parameters to our callback: previous item, which at the start is the same as our initial value so in the case previous is {} on the first iteration of the reduce; current is the value in the array we our on in our iteration; index is the index of the current element; and, array is a shallow copy of the original array. For our purposes, we shouldn't need the index or array parameters.
As we iterate through our array, we want to set the number or element as a key in the object:
arr.reduce((previous, current) => {
return {...prev, [current]: []};
}, {});
This is what this would look like on the first couple of iterations:
// 1 (first element of arr)
// returns {...{}, [1]: []} => {1: []}
// 1 (second element of arr)
// returns {...{ 1: [] }, [1]: []} => {1: []} we have a duplicate key so the previous is overwritten
// 1 (third element of arr)
// returns {...{ 1: [] }, [1]: []} => {1: []} same thing here, we have a duplicate key so the previous is overwritten
// ...
// 2 (fifth element of arr)
// returns {...{ 1: [] }, [2]: []} => {1: [], 2: []} 2 is a unique key so we add it to our object
We have an object with all of our unique keys that match all of the numbers in our array. The next step is populate each "sub array" with all the elements that match that key.
arr.reduce((previous, current) => {
return {...prev, [current]: [current]}; // n.b. [current]: allows us to use the value of a variable as a key in an obj where the right side [current] is an array with an element current
}, {});
This doesn't accomplish what we need because the previous sub will be overwritten each iteration and not appended to. This simple modification fixes that:
arr.reduce((previous, current) => {
return {...prev, [current]: [...prev[current], current]};
}, {});
The prev[current] returns the array associated with the key that matches the current item. Spreading the array with ... allows us to append the current item to the existing array.
// 1 (second element of arr)
// returns {...{ 1: [1] }, [1]: [...[1], 1]} => {1: [1, 1]}
// 1 (third element of arr)
// returns {...{ 1: [1, 1] }, [1]: [...[1, 1], 1]} => {1: [1, 1, 1]}
// ...
// 2 (fifth element of arr)
// returns {...{ 1: [1,1,1,1] }, [2]: [...[], 2]} => {1: [1,1,1,1], 2: [2]}
Quickly we will find an issue. We can't index current of undefined. In other words, when we initially start our object is empty (remember the initial value for our reduce is {}). What we have to do is create a fallback for that case which can be done simply by adding || [] meaning or an empty array:
// let's assign the return of our reduce (our object) to a variable
const groupedObj = arr.reduce((prev, current) => {
return {...prev, [current]: [...prev[current] || [], current]};
}, {});
Finally, we can convert this object to an array by using the values method on the Object type: Object.values(groupedObj).
Assertion
Here's a quick little assertion test (not comprehensive):
const arr = [1,1,1,1,2,2,3,3,3,4,5,5,6];
const groupedObj = arr.reduce(
(prev, current) => ({
...prev,
[current]: [...(prev[current] || []), current],
}),
{}
);
const groupedObjToArr = Object.values(groupedObj);
const flattenGroup = groupedObjToArr.flat(); // takes sub arrays and flattens them into the "parent" array [1, [2, 3], 4, [5, 6]] => [1, 2, 3, 4, 5, 6]
const isSameLength = arr.length === flattenGroup.length;
const hasSameElements = arr.every((x) => flattenGroup.includes(x)); // is every element in arr in our flattened array
const assertion = isSameLength && hasSameElements;
console.log(assertion); //should be true

You Can use reduce array method for this.
const arr = [1,1,1,1,2,2,3,3,3,4,5,5,6];
const resultArr = arr.reduce((item, index) =>{
if (typeof item.last === 'undefined' || item.last !== index) {
item.last = index;
item.arr.push([]);
}
item.arr[item.arr.length - 1].push(index);
return item;
}, {arr: []}).arr;
console.log(resultArr);

Here is another way to do this with just a single Array.reduce:
var arr = [1,1,1,1,2,2,3,3,3,4,5,5,6]
const grp = arr.reduce((r,c,i,a) => {
r[c] = [...r[c] || [], c]
r[c] = (a[i+1] != c && r[c].length == 1) ? r[c][0] : r[c]
return r
}, {})
console.log(Object.values(grp))
The idea is to keep track of what is coming up next in the reduce and if it is different than the current item check the current accumulator array for that item and if it is equal to 1 get the first item of it.

You can use lodash as below to get a map of elements with related duplicates
_.groupBy([6, 4, 6,6,4,2])
with the output
Object {4: [4], 6: [6, 6]}
if you want to convert it to an array you can just get the values of the object
Object.values(_.groupBy([6, 4, 6,6,4,2]))
to have the output
[[4], [6, 6]]

You can convert array to string and use regex to matchs same characters and then use .map() to prepare target structure
var arr = [1,1,1,1,2,2,3,3,3,4,5,5,6];
var newArr = arr.join('').match(/(\w)\1*/g).map(function(val){
return val.length == 1 ? +val : val.split('').map(Number);
});
console.log(newArr);

arr.sort();
new_arr = [];
arr.reduce(function (r, current_item) {
if (current_item !== r) {
new_arr.push([]);
}
new_arr[new_arr.length - 1].push(current_item);
return current_item;
}, undefined);

How about this?
const arr = [1,1,1,1,2,2,3,3,3,4,5,5,6]
const hashMap = {}
for(const num of arr) {
if (hashMap[num] !== undefined) { // To handle (0)s If any
if (Array.isArray(hashMap[num])) {
hashMap[num].push(num)
} else {
hashMap[num] = [hashMap[num], num] // add older and new value.
}
} else {
hashMap[num] = num
}
}
const result = Object.values(hashMap)
console.log(result)

You can resolve this with lodash (https://lodash.com/):
var arr = [1,1,1,1,2,2,3,3,3,4,5,5,6];
var arr2 = _.groupBy(arr);
var result = Object.keys(arr2).map(k => {return arr2[k]} );
console.log(result)
Only JS:
var arr = [1,1,1,1,2,2,3,3,3,4,5,5,6];
const groupBy = (x,f)=>x.reduce((a,b)=>((a[f(b)]||=[]).push(b),a),{});
var arr2 = groupBy (arr, v => v);
var result = Object.keys(arr2).map(k => {return arr2[k]} );
console.log(result)

Related

removing duplicate elements in an array and also the elements which is repeated most in the array should come first in the new array

const source = [2, 9, 9, 1, 6];
const ans = source.filter((item, index, arr)=> arr.indexOf(item) === index);
console.log(ans);
here i'm able to remove the duplicate elements but how to make 9 which is repeated highest to come first in the new array??
any help would be appreciated
ans should be [9, 2, 1, 6]
This should work for all cases where array should be sorted by most number of reoccurrences.
const source = [2,1,9,9,6];
const indexes = [];
var ans = source.filter((item,index,arr)=>{
if(arr.indexOf(item) === index){
indexes.push({item:item,count:1})
return true;
}
else if(arr.indexOf(item) !== index){
indexes[indexes.findIndex(object=> object.item === item)].count++
return false;
}
return false;
})
ans =(indexes.sort((a,b)=>{return b.count - a.count}).map(obj =>obj.item))
console.log(ans)
If using more space is okay, you can use a hash map for counting elements and then convert it to an array.
Something like this.
let arr = [2, 9, 9, 1, 6];
// count elements
const map = arr.reduce((acc, e) => acc.set(e, (acc.get(e) || 0) + 1), new Map());
// sort by values and convert back to array
const res = [...map.entries()].sort((a, b) => b[0] - a[0]).map((a) => {
return a[0]
});
console.log(res)
Try This
function removeAndSort(arr) {
var order = {};
for (var i = 0; i < arr.length; i++) {
var value = arr[i];
if (value in order) {
order[value]++;
} else {
order[value] = 1;
}
}
var result = [];
for (value in order) {
result.push(value);
}
function sort(a, b) {
return order[b] - order[a];
}
return result.sort(sort);
}
console.log(removeAndSort([2, 9, 9, 1, 6]));
It's Absolutely Working, Check It
Instead of removing the duplicates with the code you have you need to find a way to create a frequency map to save the duplicates information. In this example I create a map using an object like this...
const freq = { 9: [9, 2], 1: [1, 1] ... };
which uses the current iterated element as a key in an object, and the value is the element along with its duplicate value. You can grab those arrays using Object.values, sort them by that duplicate value, and then map over that sorted nested array to produce the result.
Note, however, due to the sorting process this results in [9, 1, 2, 6].
const source = [2, 9, 9, 1, 6];
// `reduce` over the array creating a key/value pair where
// the value is an array - the first element is the element value,
// and the second value is its duplicate value
const nested = source.reduce((acc, c) => {
// If the object property as defined by the element
// value doesn't exist assign an array to it initialising
// the duplicate value to zero
acc[c] ??= [c, 0];
// Increment the duplicate value
++acc[c][1];
// Return the object for the next iteration
return acc;
}, {});
// We take the `Object.values` of the object (a series of
// nested arrays and sort them by their duplicate value,
// finally `mapping` over the sorted arrays and extracting
// the first element of each
const out = Object.values(nested).sort((a, b) => {
return b[1] - a[1];
}).map(arr => arr[0]);
console.log(out);
Additional documentation
Logical nullish assignment
function sortAndFilter(source) {
let duplicates = {};
//count the duplications
source.filter((item, index, arr) => {
if(arr.indexOf(item) != index)
return duplicates[item] = (duplicates[item] || 0) + 1;
duplicates[item] = 0;
})
//sort the numbers based on the amount of duplications
return Object.keys(duplicates).map(a => parseInt(a)).sort((a, b) => duplicates[b] - duplicates[a]);
}
Output: [ 9, 6, 2, 1 ]
This could do the job
this is best answer for your question
const source = [2, 9, 9, 1, 6];
function duplicate(array) {
let duplicates = array.filter((item, index) => array.indexOf(item) !== index);
return duplicates.concat(array.filter((item) => !duplicates.includes(item)));
}
console.log(duplicate(source));
function myFunction() {
const source = [2, 9, 9, 1, 6];
const ans = source.filter((item, index, arr)=> arr.indexOf(item) === index);
ans.sort((a, b) => b-a);
console.log(ans);
}
Output: [ 9, 6, 2, 1 ]

Find all duplicates in array of objects [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.

(Javascript) i want to reduce every duplicate values in 2 Dimensional Array but i don't know how

my English is not good but i really need your help.
I want to reduce all same values in this 2 Dimensional Array but it doesn't work.
let edge = [[0,1,4],[1,2,4],[0,2,4],[2,3,4],[3,0,4],[0,2,4]];
function removeDup(edge) {
for (let i = 0; i < edge.length; i++) {
if (edge.some((item) => item > 1)) {
edge.splice(i, 1);
}
}
return edge;
}
i want to change array like this.
[[0,1,4],[1,2,4],[0,2,4],[2,3,4],[3,0,4],[0,2,4]]
to
[[0,1,4],[1,2,4],[2,3,4],[3,0,4]]
Use the the filter() array method with the every() array method as shown below:
let edge = [[0,1,4],[1,2,4],[0,2,4],[2,3,4],[3,0,4],[0,2,4]];
function removeDup(edge) {
return edge.filter(
(cur,i) => edge.slice(0,i).every(
prev => !prev.every(elm => cur.includes(elm))
)
);
}
console.log( removeDup(edge) );
//output: [[0,1,4],[1,2,4],[0,2,4],[2,3,4],[3,0,4]]
If your goal is to remove all elements that are repeated, you would need to use the whole array, edge, instead of edge.slice(0,i) and, avoid comparing an element with itself - i !== j - as shown below:
let edge = [[0,1,4],[1,2,4],[0,2,4],[2,3,4],[3,0,4],[0,2,4]];
function removeDup(edge) {
return edge.filter(
(cur,i) => edge.every(
(prev,j) => !prev.every(elm => i !== j && cur.includes(elm))
)
);
}
console.log( removeDup(edge) );
//output: [[0,1,4],[1,2,4],[2,3,4],[3,0,4]]
Another approach would be:
To convert each element array to a single value by first sorting the elements and joining them
Then use filter() to only return the element array that return a frequency of 1
Use an inner filter() to count how many times each converted element appears in the array.
[...cur] ensures original elements are not sorted, since arrays are passed by reference.
let edge = [[0,1,4],[1,2,4],[0,2,4],[2,3,4],[3,0,4],[0,2,4]];
function removeDup(edge) {
const nedge = edge.map(cur => [...cur].sort().join(''));
return edge.filter(
cur => nedge.filter(
n => n === [...cur].sort().join('')
).length === 1
);
}
console.log( removeDup(edge) );
//output: [[0,1,4],[1,2,4],[2,3,4],[3,0,4]]
This may be one possible solution to achieve the desired result:
Copying from the question:
[[0,1,4],[1,2,4],[0,2,4],[2,3,4],[3,0,4],[0,2,4]]
to
[[0,1,4],[1,2,4],[2,3,4],[3,0,4]]
Note: The desired target array has no [0, 2, 4].
Code Sample
const removeDupes = arr => (
Object.entries(
arr.reduce(
(fin, itm) =>
({...fin, [itm]: (fin[itm] || 0) + 1})
,{}
)
).filter(
([k ,v]) => v === 1
).map(x => x[0])
);
Explanation
Iterate over the array using .reduce to generate an object
The key of the resulting object will be each inner array (such as [0, 1, 4]
The value will be a count (number of times the inner array is found in edge)
Once the object is generated, iterate over its entries to filter only those which have a count of exactly 1
Now, use .map to pull only the keys of the object.
Code Snippet
let edge = [[0,1,4],[1,2,4],[0,2,4],[2,3,4],[3,0,4],[0,2,4]];
const removeDupes = arr => (
Object.entries(
arr.reduce(
(fin, itm) =>
({...fin, [itm]: (fin[itm] || 0) + 1})
,{}
)
).filter(
([k ,v]) => v === 1
).map(x => x[0])
);
console.log(removeDupes(edge));
This is the solution by using the reduce() method.
let edge = [
[0, 1, 4],
[1, 2, 4],
[0, 2, 4],
[2, 3, 4],
[3, 0, 4],
[0, 2, 4],
];
function removeDuplicate(edge) {
return edge.reduce((acc, cur) => {
!acc.some((elm) => elm.every((e, i) => cur[i] === e)) && acc.push(cur);
return acc;
}, []);
}
console.log(removeDuplicate(edge));

Double the value of each array element using Reduce

I have array of elements as input.all I need is to double the value of array elements.Though it is simple to make use of map to get the solution.I am interested in using reduce.eg:
io: var a = [1,2,3,4,5];
op:[2,4,6,8,10]; .but this is where I ended.
var c = a.reduce( (acc,b) => {
acc =b*2;
console.log(acc);
return acc
},[]);
var arr = [1, 2, 3, 4, 5];
var doubled = arr.reduce(function (memo, val) {
memo.push(val * 2);
return memo;
}, []);
console.log(doubled);
var arr2 = [1, 2, 3, 4, 5];
arr2.reduce(function (memo, val, i) {
memo[i] *= 2;
return memo;
}, arr2);
console.log(arr2);
var arr3 = [1, 2, 3, 4, 5];
arr3.reduce(function (memo, val, i) {
arr3[i] *= 2;
}, null);
console.log(arr3);
In the first solution, reduce starts with an empty array (the second argument provided to it). Then, that array is passed down to next iterations as the first argument (memo) to the function we provided. The second argument is the current element of the iteration. After the doubled value is pushed in the new array, that array is returned so it can be accessed in future iterations as memo.
In the second solution, no new array is created and the initial one is used instead. It is passed to reduce as its second element and later accessed through memo.
The third solution is like the second one except the reduced array is just referenced as it is. Notice that null must be passed as second argument. If nothing is passed, reduce will start from the second element (since there's no initial value) and the first element won't get doubled.
Note
The first time the callback is called, accumulator and currentValue can be one of two values. If no initialValue is provided, then accumulator will be equal to the first value in the array, and currentValue will be equal to the second.
let arrayOfNumbers = [1, 2, 3, 4];
arrayOfNumbers.reduce((accumulator, currentValue, index, array) => {
//code
},initialvalue);
if you miss this initialvalue argument then your index begins from one(1) and the accumulator will have the first value of array.
Hence your array[index] = array[index]*2
For example in such case
arr=[1,2,3,4,5]
output
arr=[1,4,6,8,10]
Now this will be the approach
let arrayOfNumbers = [1, 2, 3, 4];
arrayOfNumbers.reduce((accumulator, currentValue, index, array) => {
console.log(accumulator,currentValue);
array[index] = array[index]*2;
},0);
arr=[1,2,3,4,5]
output
arr=[1,4,6,8,10]
take initialvalue as 0(or any value), so that you can get the index from 0.
if you do this accumulator will get 0 and the index begins from 0 only.
Note
if you don't initialize accumulator value that is initialvalue.
Default
accumulator(initialvalue) will be arr[0]
and index begins from 1
and
if you initialize accumulator value that is initialvalue(argument) then
accumulator(initialvalue) will take that initialvalue and index begins from 0.
As you provided in your last parameter to reduce, acc is an array, although you're treating it like an integer. You'll want something like below:
var c = a.reduce( (acc,b) => {
acc.push(b*2);
console.log(acc);
return acc
},[]);
Try this
var c = a.reduce( (acc,b) => acc.concat(b*2)
,[]);
I'll provide a couple other answers that aren't shown here
1. Using spread syntax
const data =
[1,2,3,4,5];
const double = xs =>
xs.reduce ((ys, x) => [...ys, x * 2], [])
console.log(double(data))
// [ 2, 4, 6, 8, 10 ]
2. Using a destructured parameter with recursion
const data =
[1,2,3,4,5]
// this time we don't need reduce
const double = ([x,...xs]) =>
x === undefined ? [] : [x * 2, ...double(xs)]
console.log(double(data))
// [ 2, 4, 6, 8, 10 ]
3. Tacit (Point-free style)
const data =
[1,2,3,4,5]
const mult = x => y =>
y * x
const reduce = f => acc => ([x,...xs]) =>
x === undefined
? acc
: reduce (f) (f (acc, x)) (xs)
const map = f =>
reduce ((acc, x) =>
[...acc, f (x)]) ([])
// point-free double
const double =
map (mult (2))
console.log (double (data))
// [ 2, 4, 6, 8, 10 ]

Terse way to intersperse element between all elements in JavaScript array?

Say I have an array var arr = [1, 2, 3], and I want to separate each element by an element eg. var sep = "&", so the output is [1, "&", 2, "&", 3].
Another way to think about it is I want to do Array.prototype.join (arr.join(sep)) without the result being a string (because the elements and separator I am trying to use are Objects, not strings).
Is there a functional/nice/elegant way to do this in either es6/7 or lodash without something that feels clunky like:
_.flatten(arr.map((el, i) => [el, i < arr.length-1 ? sep : null])) // too complex
or
_.flatten(arr.map(el => [el, sep]).slice(0,-1) // extra sep added, memory wasted
or even
arr.reduce((prev,curr) => { prev.push(curr, sep); return prev; }, []).slice(0,-1)
// probably the best out of the three, but I have to do a map already
// and I still have the same problem as the previous two - either
// inline ternary or slice
Edit: Haskell has this function, called intersperse
Using a generator:
function *intersperse(a, delim) {
let first = true;
for (const x of a) {
if (!first) yield delim;
first = false;
yield x;
}
}
console.log([...intersperse(array, '&')]);
Thanks to #Bergi for pointing out the useful generalization that the input could be any iterable.
If you don't like using generators, then
[].concat(...a.map(e => ['&', e])).slice(1)
A spread and explicit return in reducing function will make it more terse:
const intersperse = (arr, sep) => arr.reduce((a,v)=>[...a,v,sep],[]).slice(0,-1)
// intersperse([1,2,3], 'z')
// [1, "z", 2, "z", 3]
In ES6, you'd write a generator function that can produce an iterator which yields the input with the interspersed elements:
function* intersperse(iterable, separator) {
const iterator = iterable[Symbol.iterator]();
const first = iterator.next();
if (first.done) return;
else yield first.value;
for (const value of iterator) {
yield separator;
yield value;
}
}
console.log(Array.from(intersperse([1, 2, 3], "&")));
One straightforward approach could be like feeding the reduce function with an initial array in size one less than the double of our original array, filled with the character to be used for interspersing. Then mapping the elements of the original array at index i to 2*i in the initially fed target array would do the job perfectly..
In this approach i don't see (m)any redundant operations. Also since we are not modifying any of the array sizes after they are set, i wouldn't expect any background tasks to run for memory reallocation, optimization etc.
One other good part is using the standard array methods since they check all kinds of mismatch and whatnot.
This function returns a new array, in which the called upon array's items are interspersed with the provided argument.
var arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
Array.prototype.intersperse = function(s){
return this.reduce((p,c,i) => (p[2*i]=c,p), new Array(2*this.length-1).fill(s));
}
document.write("<pre>" + JSON.stringify(arr.intersperse("&")) + "</pre>");
Using reduce but without slice
var arr = ['a','b','c','d'];
var lastIndex = arr.length-1;
arr.reduce((res,x,index)=>{
res.push(x);
if(lastIndex !== index)
res.push('&');
return res;
},[]);
If you have Ramda in your dependencies or if willing to add it, there is intersperse method there.
From the docs:
Creates a new list with the separator interposed between elements.
Dispatches to the intersperse method of the second argument, if present.
R.intersperse('n', ['ba', 'a', 'a']); //=> ['ba', 'n', 'a', 'n', 'a']
Or you can check out the source for one of the ways to do it in your codebase. https://github.com/ramda/ramda/blob/v0.24.1/src/intersperse.js
You could use Array.from to create an array with the final size, and then use the callback argument to actually populate it:
const intersperse = (arr, sep) => Array.from(
{ length: Math.max(0, arr.length * 2 - 1) },
(_, i) => i % 2 ? sep : arr[i >> 1]
);
// Demo:
let res = intersperse([1, 2, 3], "&");
console.log(res);
ONE-LINER and FAST
const intersperse = (ar,s)=>[...Array(2*ar.length-1)].map((_,i)=>i%2?s:ar[i/2]);
console.log(intersperse([1, 2, 3], '&'));
javascript has a method join() and split()
var arr = ['a','b','c','d'];
arr = arr.join('&');
document.writeln(arr);
Output should be: a&b&c&d
now split again:
arr = arr.split("");
arr is now:
arr = ['a','&','b','&','c','&','d'];
if (!Array.prototype.intersperse) {
Object.defineProperty(Array.prototype, 'intersperse', {
value: function(something) {
if (this === null) {
throw new TypeError( 'Array.prototype.intersperse ' +
'called on null or undefined' );
}
var isFunc = (typeof something == 'function')
return this.concat.apply([],
this.map(function(e,i) {
return i ? [isFunc ? something(this[i-1]) : something, e] : [e] }.bind(this)))
}
});
}
you can also use the following:
var arr =['a', 'b', 'c', 'd'];
arr.forEach(function(element, index, array){
array.splice(2*index+1, 0, '&');
});
arr.pop();
My take:
const _ = require('lodash');
_.mixin({
intersperse(array, sep) {
return _(array)
.flatMap(x => [x, sep])
.take(2 * array.length - 1)
.value();
},
});
// _.intersperse(["a", "b", "c"], "-")
// > ["a", "-", "b", "-", "c"]
const arr = [1, 2, 3];
function intersperse(items, separator) {
const result = items.reduce(
(res, el) => [...res, el, separator], []);
result.pop();
return result;
}
console.log(intersperse(arr, '&'));
A few years later, here's a recursive generator solution. Enjoy!
const intersperse = function *([first, ...rest], delim){
yield first;
if(!rest.length){
return;
}
yield delim;
yield * intersperse(rest, delim);
};
console.log([...intersperse(array, '&')]);
export const intersperse = (array, insertSeparator) => {
if (!isArray(array)) {
throw new Error(`Wrong argument in intersperse function, expected array, got ${typeof array}`);
}
if (!isFunction(insertSeparator)) {
throw new Error(`Wrong argument in intersperse function, expected function, got ${typeof insertSeparator}`);
}
return flatMap(
array,
(item, index) => index > 0 ? [insertSeparator(item, index), item] : [item] // eslint-disable-line no-confusing-arrow
);
};
Here is also a version with reduce only:
const intersperse = (xs, s) => xs.reduce((acc, x) => acc ? [...acc, s, x] : [x], null)
const a = [1, 2, 3, 4, 5]
console.log(intersperse(a, 0))
// [1, 0, 2, 0, 3, 0, 4, 0, 5]
Updated for objects not using join method:
for (var i=0;i<arr.length;i++;) {
newarr.push(arr[i]);
if(i>0) {
newarr.push('&');
}
}
newarr should be:
newarr = ['a','&','b','&','c','&','d'];

Categories