Преобразование lodash _.uniqBy() в нативный JavaScript
Здесь, в этом фрагменте, я застрял как _.uniqBy(array,iteratee)
,этот
iteratee
может быть функцией или строкой одновременно- Где поставить условие для проверки уникальности свойства, потому что функция itratee может быть чем угодно
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)
Любые выводы по этому вопросу будут оценены по достоинству.
5 ответов
ES6 uniqBy
с помощью Map
со сложностью O(n):
const uniqBy = (arr, predicate) => {
const cb = typeof predicate === 'function' ? predicate : (o) => o[predicate];
return [...arr.reduce((map, item) => {
const key = cb(item);
map.has(key) || map.set(key, item);
return map;
}, new Map()).values()];
};
const sourceArray = [
{ id: 1, name: 'bob' },
{ id: 1, name: 'bill' },
{ id: 1, name: 'bill' } ,
{ id: 2,name: 'silly'},
{ id: 2,name: 'billy'}
];
console.log('id string: ', uniqBy(sourceArray, 'id'));
console.log('name func: ', uniqBy(sourceArray, (o) => o.name));
Реорганизовано решение @ori-drori и удалено
undefined
null
- дополнительные числа в смешанном массиве
- возвращение
[]
если первый параметр не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);
Я запускаю свой код через Webpack через CreateReactApp, он должен использовать полифилл для распространения, который использует срез. Вот что я сделал вместо этого, вариант ответа @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;
};
Вы можете использовать сортировку, упорядоченную по имени, и фильтр на основе сравнения окрестностей, например так:
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)