给定以下数组:
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,
}
})