将 Lodash 的 _.uniqBy() 转换为原生 JavaScript

问题描述 投票:0回答:5

在这个片段中,我被困在

_.uniqBy(array, iteratee)
中。这个

  • iteratee
    可以同时是函数或字符串
  • 在哪里放置条件来检查属性的唯一性,因为 iteratee 函数可以是任何东西

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

function uniqBy (inputArray, callback) {
  return inputArray.filter(callback)
}
var inputFunc = function (item) {
  return item.name
}

// var destArray = _.uniqBy(sourceArray,'name')

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

解决办法是什么?

javascript arrays lodash distinct-values
5个回答
35
投票

使用

uniqBy
 的 ES6 
Map
,复杂度为 O(n):

const uniqBy = (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;
  }, new Map()).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));


3
投票

我重构了ori-drori的解决方案并删除了

  1. undefined
  2. null
  3. 混合数组中的额外数字
  4. 如果第一个参数不是
    []
    则返回
    Array

const uniqBy = (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);
    }, new Map())
    .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);


2
投票

我正在通过 CreateReactApp 通过 Webpack 运行我的代码,它必须使用使用切片的 polyfill 进行传播。这就是我所做的,@oridori 答案的变体:

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

  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;
};

2
投票

对于那些寻找一行答案的人:

const inputArr = [
  { id: 1, name: { first: 'bob' } },
  { id: 1, name: { first: 'bill' } },
  { id: 1, name: { first: 'bill' } },
  { id: 1 },
  undefined,
  { id: 2, name: { first: 'silly' } },
  { id: 2, name: { first: 'billy' } }
]
var uniqBy = (arr, key) => {
  return Object.values([...arr].reverse().reduce((m, i) => {m[key.split('.').reduce((a, p) => a?.[p], i)] = i; return m;}, {}))
}
console.log(uniqBy(inputArr, 'id'))
console.log(uniqBy(inputArr, 'name.first'))


0
投票

您可以使用按名称排序的排序和基于邻域比较的过滤器,如下所示:

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

var uniqBy = (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]));
var inputFunc = item => item.name;


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

© www.soinside.com 2019 - 2024. All rights reserved.