通过对象数组进行映射,并添加具有相同属性值的元素的计数器



给定以下数组:

const arr = [
{color: 'red'}, 
{color: 'red'}, 
{color: 'green'}, 
{color: 'blue'}, 
{color: 'blue'}, 
{color: 'red'}]

如何通过其元素进行映射,以创建一个用属性colorIndex扩展的对象数组,该数组将作为有多少先前元素具有相同color属性的计数器?

结果将是以下数组:

[
{color: 'red', colorIndex: 0}, 
{color: 'red', colorIndex: 1}, 
{color: 'green', colorIndex: 0}, 
{color: 'blue', colorIndex: 0}, 
{color: 'blue', colorIndex: 1}, 
{color: 'red', colorIndex: 2}
]

有什么优雅的解决方案可以实现这一点吗?

编辑:

根据@FZs的评论,我发布了更快(更清晰(的解决方案。它需要更少的操作来完成;脑力;(又称认知负荷(阅读;(

const arr = [
{ color: 'red' },
{ color: 'red' },
{ color: 'green' },
{ color: 'blue' },
{ color: 'blue' },
{ color: 'red' }
]
var countByColor = new Map();
console.log(
arr.map(function mapArray(elem, index) {
var color = elem.color;
var count = countByColor.get(color) || 0;
countByColor.set(color, count + 1); // add 1, so next time we spot the color it will get correct counter
return {
color, count
}
})
)

新旧性能测试:https://jsbench.me/7kkx5zffpm/2


原始答案:

好吧,不确定你为什么要问,你已经尝试了什么来解决这个问题。在完全没有上下文的情况下,很难得到正确的答案。但这是我的方法,也许你会知道一点:

arr.map((elem, index) => {
// we only care about values before current index, to see how many elements with given color were **before**
var colors = arr.map((obj) => obj.color).splice(0, index + 1);
return {
...elem, // using spread operator to get all properties of original object
count: colors.reduce(
(prev, curr) => (curr == elem.color ? prev + 1 : prev),
-1 // starting from -1 to get 0-based counter
),
};
})

点击stackblitz查看:https://stackblitz.com/edit/js-bnru4m

阅读有关reduce的更多信息:https://developer.mozilla.org/pl/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

阅读有关spread运算符的更多信息:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax

阅读有关拼接阵列的更多信息:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice

阅读有关映射数组的更多信息:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map

我想到的第一个解决方案并不优雅,但它会成功的。最好是使用一个额外的对象。

const foundItems = {};
arr.map(item => {
let foundItem = foundItems[item.color] ? foundItems[item.color]+ 1 : 0;
foundItems[item.color] = founditem;
return {
...item,
colorIndex: foundItem,
}
})

最新更新