JavaScript将数组转换为以数组属性为键的映射,并将相应的重复键值存储为数组

3

我有一个数组,其中包含一些对象,对象的一个属性可以有重复,例如Account。现在,我想将这个数组转换为Map,其中键具有Account属性值,并且相应的重复项应该存储为该键在Map中的数组。

let arr = [];
arr.push({'Key':'1','Record':{'Account':'a','data':'A1'}});
arr.push({'Key':'2','Record':{'Account':'b','data':'123'}});
arr.push({'Key':'3','Record':{'Account':'a','data':'A2'}});
arr.push({'Key':'4','Record':{'Account':'a','data':'A3'}});
arr.push({'Key':'5','Record':{'Account':'c','data':'123'}});
const  accIdMap=  arr.reduce((map,obj) => (map[obj.Record.Account] = obj,map), {});
console.log(arr);
console.log(accIdMap);

目前accIdMap只得到一对一的键值映射,即最后一个推入数组中的键值对,即4。但我希望输出的映射表中,如果键重复,则该值应为数组。我尝试过缩减,但这会消除重复值,而我希望重复的值保留相应的数组。

例如

现有输出结果:

{
  "a": {
    "Key": "4",
    "Record": {
      "Account": "a",
      "data": "A3"
    }
  },
  "b": {
    "Key": "2",
    "Record": {
      "Account": "b",
      "data": "123"
    }
  },
  "c": {
    "Key": "5",
    "Record": {
      "Account": "c",
      "data": "123"
    }
  }
}

期望输出(重复的键应该将值添加为数组)

{
  "a": [{"Key": "4","Record": {"Account": "a","data": "A3"}},{
    "Key": "3",
    "Record": {
      "Account": "a",
      "data": "A2"
    }
  },{
    "Key": "1",
    "Record": {
      "Account": "a",
      "data": "A1"
    }
  }],
  "b": {
    "Key": "2",
    "Record": {
      "Account": "b",
      "data": "123"
    }
  },
  "c": {
    "Key": "5",
    "Record": {
      "Account": "c",
      "data": "123"
    }
  }
}
3个回答

3
你可以这样使用 reduce
检查 accumulator 是否已经具有当前 a.Record.Account 键。如果是,则将当前项推送到其上下文中。否则,将 a.Record.Account 添加为一个键,然后将该项推送到其中。

const input = [{'Key':'1','Record':{'Account':'a','data':'A1'}},
{'Key':'2','Record':{'Account':'b','data':'123'}},
{'Key':'3','Record':{'Account':'a','data':'A2'}},
{'Key':'4','Record':{'Account':'a','data':'A3'}},
{'Key':'5','Record':{'Account':'c','data':'123'}}]

const output = input.reduce((acc, a) => 
      ((acc[a.Record.Account] = acc[a.Record.Account] || []).push(a), acc), {})
console.log(output);


1
在reduce函数中进行检查,如果值已经存在,则可以根据此执行以下操作。如果帐户已经存在,则检查映射是否具有该帐户键上的数组。如果没有,请通过创建空数组并将其推入其中来使用现有元素和当前元素创建数组。如果它是一个数组,那么只需将其推入即可。如果帐户键不存在,则将该值设置为obj。
更新:重新排序了const m的初始化并添加了代码注释。

let arr = [];
arr.push({'Key':'1','Record':{'Account':'a','data':'A1'}});
arr.push({'Key':'2','Record':{'Account':'b','data':'123'}});
arr.push({'Key':'3','Record':{'Account':'a','data':'A2'}});
arr.push({'Key':'4','Record':{'Account':'a','data':'A3'}});
arr.push({'Key':'5','Record':{'Account':'c','data':'123'}});
const  accIdMap=  arr.reduce((map,obj) => {
    if(map[obj.Record.Account]) { // the property exists and can be an array or the obj
        if(!map[obj.Record.Account].length) { // means just the object. Creating an array then pushing the existing obj to it
            const m = (map[obj.Record.Account]);
            map[obj.Record.Account] = [];
            map[obj.Record.Account].push(m);
        }
        map[obj.Record.Account].push(obj); // if it was an array this will push it to the existing array. If it wasn't the previous if have created and inserted old value and this line pushes to the new array
    } else {
        map[obj.Record.Account] = obj; // just putting the obj value as it wasn't a duplicate
    }
    return map;
}, {});
console.log(arr);
console.log(accIdMap);


0

这个工作就像你期望的那样。拿到这个结果,与你想要的输出进行匹配。

let arr = [];
arr.push({ 'Key': '1', 'Record': { 'Account': 'a', 'data': 'A1' } });
arr.push({ 'Key': '2', 'Record': { 'Account': 'b', 'data': '123' } });
arr.push({ 'Key': '3', 'Record': { 'Account': 'a', 'data': 'A2' } });
arr.push({ 'Key': '4', 'Record': { 'Account': 'a', 'data': 'A3' } });
arr.push({ 'Key': '5', 'Record': { 'Account': 'c', 'data': '123' } });
var obj = {}
arr.map((e) => {
    var filteredArr = arr.filter((f) => f.Record.Account == e.Record.Account)
    if (filteredArr.length > 1)
        obj[e.Record.Account] = filteredArr
    else if (filteredArr.length != 0)
        obj[e.Record.Account] = filteredArr[0]
})
console.log(JSON.stringify(obj))


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接