Skip to content Skip to sidebar Skip to footer

Converting Lodash _.uniqby() To Native Javascript

Here in this snippet i am stuck as in _.uniqBy(array,iteratee),this iteratee can be a function or a string at the same time Where to put the condition to check uniqness on the pr

Solution 1:

An ES6 uniqBy using Map with a complexity of O(n):

constuniqBy = (arr, predicate) => {
  const cb = typeof predicate === 'function' ? predicate : (o) => o[predicate];
  
  return [...arr.reduce((map, item) => {
    const key = (item === null || item === undefined) ? 
      item : cb(item);
    
    map.has(key) || map.set(key, item);
    
    return map;
  }, newMap()).values()];
};

const sourceArray = [ 
  { id: 1, name: 'bob' },
  { id: 1, name: 'bill' },
  null,
  { id: 1, name: 'bill' } ,
  { id: 2,name: 'silly'},
  { id: 2,name: 'billy'},
  null,
  undefined
];

console.log('id string: ', uniqBy(sourceArray, 'id'));

console.log('name func: ', uniqBy(sourceArray, (o) => o.name));

Solution 2:

Refactored @ori-drori's solution and removed

  1. undefined
  2. null
  3. extra numbers in mixed array
  4. return [] if first param is not Array

constuniqBy = (arr, predicate) => {
  if (!Array.isArray(arr)) { return []; }

  const cb = typeof predicate === 'function' ? predicate : (o) => o[predicate];

  const pickedObjects = arr
    .filter(item => item)
    .reduce((map, item) => {
        const key = cb(item);

        if (!key) { return map; }

        return map.has(key) ? map : map.set(key, item);
    }, newMap())
    .values();
 
  return [...pickedObjects];
};

const a = [ 
  12,
  undefined,
  { id: 1, name: 'bob' },
  null,
  { id: 1, name: 'bill' },
  null,
  undefined
];

const b = [ 
  12,
  { id: 1, name: 'bob' },
  { id: 1, name: 'bill' },
];

uniqBy(a, 'name');
uniqBy(b, Math.floor);
uniqBy([2.1, 1.2, 2.3], Math.floor);

Solution 3:

I'm running my code through Webpack via CreateReactApp, it must be using a polyfill for spread that uses slice. Here's what I did instead, a variation of @oridori's answer:

constuniqBy = (arr: any[], predicate: (item: any) => string) => {
  const cb = typeof predicate === 'function' ? predicate : (o) => o[predicate];
  const result = [];
  const map = newMap();

  arr.forEach((item) => {
    const key = (item === null || item === undefined) ? item : cb(item);

    if (!map.has(key)) {
      map.set(key, item);
      result.push(item);
    }
  });

  return result;
};

Solution 4:

You could use a sort ordered by name and a filter based on the neighborhood comparison like this :

var sourceArray = [ { id: 1, name: 'bob' },
  { id: 1, name: 'bill' },
  { id: 1, name: 'bill' } ,
  {id: 2,name: 'silly'},
  {id: 2,name: 'billy'}]

varuniqBy = (inputArray, callback) => inputArray.sort((a,b) =>callback(a) > callback(b))
.filter((x,i,arr) => i === arr.length -1 ? true : callback(x) !== callback(arr[i+1]));
varinputFunc = item => item.name;


var destArray = uniqBy(sourceArray, inputFunc)
console.log('destArray', destArray)

Post a Comment for "Converting Lodash _.uniqby() To Native Javascript"