zianwar
zianwar

Reputation: 3750

lodash: Get duplicate values from an array

Say I have an array like this: [1, 1, 2, 2, 3]

I want to get the duplicates which are in this case: [1, 2]

Does lodash support this? I want to do it in the shortest way possible.

Upvotes: 41

Views: 83171

Answers (12)

saadel
saadel

Reputation: 1757

You can use this:

_.filter(arr, (val, i, iteratee) => _.includes(iteratee, val, i + 1))

or without using lodash, you can use plain JavaScript:

arr.filter((val, i) => arr.includes(val, i + 1))

Note: that if a number appears more than two times in your array you can always use _.uniq.

Upvotes: 57

Vladyslav Frizen
Vladyslav Frizen

Reputation: 227

Pure JS solution:

export function hasDuplicates(array) {
  return new Set(array).size !== array.length
}

For an array of objects:

/**
 * Detects whether an array has duplicated objects.
 * 
 * @param array
 * @param key
 */
export const hasDuplicatedObjects = <T>(array: T[], key: keyof T): boolean => {
  const _array = array.map((element: T) => element[key]);

  return new Set(_array).size !== _array.length;
};

Upvotes: 6

adiga
adiga

Reputation: 35259

You can make use of a counter object. This will have each number as key and total number of occurrence as their value. You can use filter to get the numbers when the counter for the number becomes 2

const array = [1, 1, 2, 2, 3],
      counter = {};
      
const duplicates = array.filter(n => (counter[n] = counter[n] + 1 || 1) === 2)

console.log(duplicates)

Upvotes: 1

Hushen Savani
Hushen Savani

Reputation: 1

No need to use lodash, you can use following code:

function getDuplicates(array, key) {
  return array.filter(e1=>{
    if(array.filter(e2=>{
      return e1[key] === e2[key];
    }).length > 1) {
      return e1;
    }
  })
}

Upvotes: 0

Akrion
Akrion

Reputation: 18525

Here is another concise solution:

let data = [1, 1, 2, 2, 3]

let result = _.uniq(_.filter(data, (v, i, a) => a.indexOf(v) !== i))

console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

_.uniq takes care of the dubs which _.filter comes back with.

Same with ES6 and Set:

let data = [1, 1, 2, 2, 3]

let result = new Set(data.filter((v, i, a) => a.indexOf(v) !== i))

console.log(Array.from(result))

Upvotes: 3

Vijay Kesanupalli
Vijay Kesanupalli

Reputation: 165

Hope below solution helps you and it will be useful in all conditions

  hasDataExist(listObj, key, value): boolean {
    return _.find(listObj, function(o) { return _.get(o, key) == value }) != undefined;
  }



  let duplcateIndex = this.service.hasDataExist(this.list, 'xyz', value);

Upvotes: 0

vonsko
vonsko

Reputation: 394

here is mine, es6-like, deps-free, answer. with filter instead of reducer

// this checks if elements of one list contains elements of second list 
// example code
[0,1,2,3,8,9].filter(item => [3,4,5,6,7].indexOf(item) > -1)

// function
const contains = (listA, listB) => listA.filter(item => listB.indexOf(item) > -1) 
contains([0,1,2,3], [1,2,3,4]) // => [1, 2, 3]

// only for bool
const hasDuplicates = (listA, listB) => !!contains(listA, listB).length

edit: hmm my bad is: I've read q as general question but this is strictly for lodash, however my point is - you don't need lodash in here :)

Upvotes: 1

Rahul Surabhi
Rahul Surabhi

Reputation: 46

Well you can use this piece of code which is much faster as it has a complexity of O(n) and this doesn't use Lodash.

[1, 1, 2, 2, 3]
.reduce((agg,col) => {
  agg.filter[col] = agg.filter[col]? agg.dup.push(col): 2;
  return agg
 },
 {filter:{},dup:[]})
.dup;

//result:[1,2]

Upvotes: 1

gafi
gafi

Reputation: 12824

Another way is to group by unique items, and return the group keys that have more than 1 item

_([1, 1, 2, 2, 3]).groupBy().pickBy(x => x.length > 1).keys().value()

Upvotes: 36

Brian Park
Brian Park

Reputation: 2577

How about using countBy() followed by reduce()?

const items = [1,1,2,3,3,3,4,5,6,7,7];

const dup = _(items)
    .countBy()
    .reduce((acc, val, key) => val > 1 ? acc.concat(key) : acc, [])
    .map(_.toNumber)

console.log(dup);
// [1, 3, 7]

http://jsbin.com/panama/edit?js,console

Upvotes: 6

Rafael Zeffa
Rafael Zeffa

Reputation: 2424

Another way, but using filters and ecmaScript 2015 (ES6)

var array = [1, 1, 2, 2, 3];

_.filter(array, v => 
  _.filter(array, v1 => v1 === v).length > 1);

//→ [1, 1, 2, 2]

Upvotes: 6

Mikhail Romanov
Mikhail Romanov

Reputation: 1612

var array = [1, 1, 2, 2, 3];
var groupped = _.groupBy(array, function (n) {return n});
var result = _.uniq(_.flatten(_.filter(groupped, function (n) {return n.length > 1})));

This works for unsorted arrays as well.

Upvotes: 18

Related Questions