#javascript #arrays #ecmascript-6 #javascript-objects #ecmascript-5
#javascript #массивы #ecmascript-6 #javascript-объекты #ecmascript-5
Вопрос:
Я пытаюсь получить элементы dropdwon из тегов и ключевых слов. Я попытался привести их к одному и тому же формату для каждой из них, фильтруя и отображая следующим образом:
const productsWithTags = products
.filter(product => !!product.tagId)
.map(item => ({
id: item.tagId,
name: item.tagName,
}))
Дело в том, что он добавляет дубликаты, поскольку некоторые продукты имеют одинаковые идентификаторы тегов, как я могу сохранить этот массив уникальным?
Ответ №1:
Сначала вам нужно выбрать отдельные элементы по идентификатору тега, а затем сопоставить результат
const products= [{tagId:1,tagName:"Tag 1"}, {tagId:2,tagName:"Tag 2"}, {tagId:3,tagName:"Tag 3"}, {tagId:1,tagName:"Tag 1-2"}, {tagId:3,tagName:"Tag 3-2"}, {tagId:2,tagName:"Tag 2-2"}]
const productsWithTags = products
.filter(function(value,index,self){return self.indexOf(self.find(item =>item.tagId==value.tagId)) === index})
.map(item => ({
id: item.tagId,
name: item.tagName,
}))
console.log(productsWithTags)
Комментарии:
1. Вы также можете использовать findIndex напрямую вместо
insteadOf
find
Ответ №2:
Вместо tagId
того, чтобы приводить свойство к a Boolean
, вы должны создать таблицу поиска, которая сообщает вам, был ли tagId
элемент уже просмотрен / посещен, а затем фильтровать на основе этого результата.
Ниже вы можете увидеть рабочий пример с аннотациями.
const products = [
{
tagId: 'a',
tagName: 'Tag A'
},
{
tagId: 'b',
tagName: 'Tag B'
},
{
tagId: 'a',
tagName: 'Tag A'
},
{
tagId: 'c',
tagName: 'Tag C'
}
];
function uniqueBy(property) {
let seen = Object.create(null); // closure, tells us the already seen id's
return function (item) { // predicate function
let key = item[property]; // get the "key" value (here: tagId)
if (seen[key] == null) { // is the key not inside the seen closure?
seen[key] = 1; // then add it and
return true; // accept the item
}
return false; // otherwise reject the item
};
}
const result = products.
filter(uniqueBy('tagId')). // use "uniqueBy" to create a predicate
map(product => {
return {
id: product.tagId,
name: product.tagName
};
});
console.log(result);
Подсказка: вы можете сделать это более производительным, избегая одного шага итерации. Как? Используйте .reduce
вместо .filter
и .map
.
const products = [
{
tagId: 'a',
tagName: 'Tag A'
},
{
tagId: 'b',
tagName: 'Tag B'
},
{
tagId: 'a',
tagName: 'Tag A'
},
{
tagId: 'c',
tagName: 'Tag C'
}
];
function uniqueBy(property) {
let seen = Object.create(null); // closure, tells us the already seen id's
return function (item) { // predicate function
let key = item[property]; // get the "key" value (here: tagId)
if (seen[key] == null) { // is the key not inside the seen closure?
seen[key] = 1; // then add it and
return true; // accept the item
}
return false; // otherwise reject the item
};
}
function filterMap(filterer, mapper) {
return function (accumulator, item) {
return filterer(item)
? [...accumulator, mapper(item)]
: accumulator;
}
}
const result = products.
reduce(
filterMap(
uniqueBy('tagId'),
product => {
return {
id: product.tagId,
name: product.tagName
};
}
),
[]
);
console.log(result);