【问题标题】:Group nested array of objects分组嵌套对象数组
【发布时间】:2020-05-16 04:36:32
【问题描述】:

我有以下对象:

const attributes = [
    {
        id: "a",
        values: [
            {
                value: [
                    {
                        _id: "aa",
                        value: "1500"
                    },
                    {
                        _id: "ab",
                        value: "580"
                    }
                ]
            },
            {
                value: [
                    {
                        _id: "aa",
                        value: "400"
                    }
                ]
            }
        ]
    },
    {
        id: "a",
        values: [
            {
                value: [
                    {
                        _id: "aa",
                        value: "420"
                    },
                    {
                        _id: "ab",
                        value: "300"
                    }
                ]
            },
            {
                value: [
                    {
                        _id: "aa",
                        value: "480"
                    },
                    {
                        _id: "ab",
                        value: "1000"
                    }
                ]
            },
            {
                value: [
                    {
                        _id: "aa",
                        value: "880"
                    },
                    {
                        _id: "ab",
                        value: "740"
                    }
                ]
            }
        ]
    },
    {
        id: "b",
        values: [
            {
                value: [
                    {
                        _id: "ba",
                        value: "1500"
                    },
                    {
                        _id: "bb",
                        value: "580"
                    }
                ]
            },
            {
                value: [
                    {
                        _id: "ba",
                        value: "400"
                    }
                ]
            }
        ]
    },
];

我想根据属性id和值_id对数据进行分组,所以我可以得到以下对象作为回报:

[
    {
        id: "a",
        values: [
            {
                value: [
                    {
                        _id: "aa",
                        values: ["1900", "1780"]
                    },
                    {
                        _id: "ab",
                        values: ["580", "2040"]
                    }
                ]
            }
        ]
    },
    {
        id: "b",
        values: [
            {
                value: [
                    {
                        _id: "ba",
                        values: ["1900"]
                    },
                    {
                        _id: "bb",
                        values: "[580"]
                    }
                ]
            },
        ]
    },
];

如果结果没有意义,我可以解释更多。 无论如何,我尝试通过执行以下操作来尝试结果,但它没有按预期工作,我相信有一种更清洁的方法可以做到这一点。

let newAttributes = [];
attributes.forEach(attribute => {
    let currentAttribute = { id: attribute.id, values: attribute.values[0] };
    attribute.values.shift();
    attribute.values.forEach(attributeValues => {
        attributeValues.value.forEach(vl => {
            var values = currentAttribute.values.value.find(vl2 => vl2._id === vl._id);
            if (values && attribute.id === currentAttribute.id) {
                if (!values.values) {
                    values.values = [];
                }
                values.values.push(vl.value);
            }
        });
    });
    newAttributes.push(attributes);
});

newAttributes.forEach(attribute => {
    attribute.values.value.forEach(vl => {
        if (vl.values) {
            vl.values.push(vl.value);
        } else {
            vl.values = [vl.value]
        }
        delete vl.value;
    });
    attribute.values.value.forEach(vl => {
        vl.values = vl.values.reduce((a, b) => {
            return Number(a) + Number(b);
        }, 0);
         vl.values =  [vl.values.toString()]
    });
});

console.log(newAttributes);

编辑:

说明:我们以属性id = 'a'和值_id = 'aa'为例:

对于带有id = 'a' 的第一个属性,我们有两个带有_id = 'aa' 的值,一个具有1500,另一个具有400,我们将它们相加我们得到了两个值 1900,然后我们有另一个属性 id = 'a' 有 3 个值 _id = 'aa',值 420480880,这些值的总和是 1780,我们将这个总和推入具有_id = 'aa' 的第一个属性的值id = 'a'

【问题讨论】:

  • 预期输出不干净
  • @brk 请看我的编辑,我添加了解释。

标签: javascript arrays json object


【解决方案1】:

const attributes = [
    {
        id: "a",
        values: [
            {
                value: [
                    {
                        _id: "aa",
                        value: "1500"
                    },
                    {
                        _id: "ab",
                        value: "580"
                    }
                ]
            },
            {
                value: [
                    {
                        _id: "aa",
                        value: "400"
                    }
                ]
            }
        ]
    },
    {
        id: "a",
        values: [
            {
                value: [
                    {
                        _id: "aa",
                        value: "420"
                    },
                    {
                        _id: "ab",
                        value: "300"
                    }
                ]
            },
            {
                value: [
                    {
                        _id: "aa",
                        value: "480"
                    },
                    {
                        _id: "ab",
                        value: "1000"
                    }
                ]
            },
            {
                value: [
                    {
                        _id: "aa",
                        value: "880"
                    },
                    {
                        _id: "ab",
                        value: "740"
                    }
                ]
            }
        ]
    },
    {
        id: "b",
        values: [
            {
                value: [
                    {
                        _id: "ba",
                        value: "1500"
                    },
                    {
                        _id: "bb",
                        value: "580"
                    }
                ]
            },
            {
                value: [
                    {
                        _id: "ba",
                        value: "400"
                    }
                ]
            }
        ]
    },
];

let newStructure = 
	attributes.map(attr => {
		let tempValues = {};
		attr.values.forEach((value, index)=> { 
			value.value.forEach((v)=>{
				if(typeof tempValues[v._id] == "undefined")
					tempValues[v._id] = 0;
				tempValues[v._id] += +v.value

			})
		})
		return {
			id: attr.id,
			values: tempValues
		}

}).reduce((accumulator, currentValue)=>{
	if(typeof accumulator[currentValue.id] == "undefined")
		accumulator[currentValue.id] = { id: currentValue.id, values: {} };
	Object.keys(currentValue.values).forEach( valueKey =>{
		if(typeof accumulator[currentValue.id].values[valueKey] == "undefined")
				accumulator[currentValue.id].values[valueKey] = [currentValue.values[valueKey]];
		else
				accumulator[currentValue.id].values[valueKey].push(currentValue.values[valueKey]);
	})
	
	return accumulator
},{})

newStructure = Object.keys(newStructure).map(itemKey => {
	return {
		id: itemKey,
		values: {
			value: Object.keys(newStructure[itemKey].values).map(valueKey => {
				return  {
					_id: valueKey,
					value: newStructure[itemKey].values[valueKey]
				}
			})
		}
	}
});

console.log(newStructure)

【讨论】:

    【解决方案2】:

    使用更直接/原生的 javascript 对象形式,我能够使大多数部分更加离散。此代码通常假定对象可能没有给定索引的初始值,因此不会根据您在 attribute.values[0] 初始化和未来仅使用这些索引的假设执行任何优化。

    let newAttributes = {}; // will be converted back
    for (attribute of attributes){
    
        let newValues = []; // turn it into [ { "aa":1500, "ab":580 }, {"aa":400} ]
        for (valueSet of attribute.values){
            let newObj = {};
            for (value of valueSet.value){
                newObj[value._id] = Number(value.value);
            }
            newValues.push(newObj);
        }
    
        let sum = {};
        for (value of newValues){
            for (id in value){
                if (!(id in sum)) sum[id] = 0;
                sum[id] += value[id];
            }
        }
    
        if ( !(attribute.id in newAttributes))
            newAttributes[attribute.id] = {};
    
        outAttrib = newAttributes[attribute.id]
        for (id in sum){
            if ( !(id in outAttrib)) outAttrib[id] = [];
            outAttrib[id].push(sum[id].toString());
        }
    
    }
    // at this point, the object would be in, imo, more manageable form
    // a: { aa: [ '1900', '1780' ], ab: [ '580', '2040' ] },
    // b: { ba: [ '1900' ], bb: [ '580' ] }
    
    let out = [];
    for (id in newAttributes){ // can be integrated into former loop but I think this makes more sense
        let value = [];
        for (_id in newAttributes[id]){
            value.push({_id: _id, values: newAttributes[id][_id]});
        }
        out.push({id: id, values: [ { value: value } ] });
    }
    console.log(out);
    

    【讨论】:

      【解决方案3】:

      我从头开始编写代码,它正在工作

      const attributes = [
        {
            id: "a",
            values: [
                {
                    value: [
                        {
                            _id: "aa",
                            value: "1500"
                        },
                        {
                            _id: "ab",
                            value: "580"
                        }
                    ]
                },
                {
                    value: [
                        {
                            _id: "aa",
                            value: "400"
                        }
                    ]
                }
            ]
        },
        {
            id: "a",
            values: [
                {
                    value: [
                        {
                            _id: "aa",
                            value: "420"
                        },
                        {
                            _id: "ab",
                            value: "300"
                        }
                    ]
                },
                {
                    value: [
                        {
                            _id: "aa",
                            value: "480"
                        },
                        {
                            _id: "ab",
                            value: "1000"
                        }
                    ]
                },
                {
                    value: [
                        {
                            _id: "aa",
                            value: "880"
                        },
                        {
                            _id: "ab",
                            value: "740"
                        }
                    ]
                }
            ]
        },
        {
            id: "b",
            values: [
                {
                    value: [
                        {
                            _id: "ba",
                            value: "1500"
                        },
                        {
                            _id: "bb",
                            value: "580"
                        }
                    ]
                },
                {
                    value: [
                        {
                            _id: "ba",
                            value: "400"
                        }
                    ]
                }
            ]
        },
      ];
      
      newAttributes = [];
      attributes.forEach(attribute => {
        childOutput = childNode(attribute.values)
      
        var isIdPresent = newAttributes.filter(e => {
          return  e.id == attribute.id
        });
      
        if (isIdPresent.length > 0) {
          var parentNode = isIdPresent[0]
          newAttributes = newAttributes.filter(e => {
            return  e.id != attribute.id
          });
          parentNode["values"][0].value = (mergeChildNode(parentNode["values"][0].value, childOutput))
          newAttributes.push(parentNode)
        } else {
          var parentNode ={}
          parentNode["id"] = attribute.id
          parentNode["values"] = [{value:[]}]
          parentNode["values"][0].value = (mergeChildNode(parentNode["values"][0].value, childOutput))
          newAttributes.push(parentNode)
        }
      });
      
      console.log(JSON.stringify(newAttributes));
      
      
      function childNode(attrValues){
        childOutput = {}
        attrValues.forEach(valueArray => {
          valueArray.value.forEach(valueObj => {
            if (childOutput.hasOwnProperty(valueObj._id)) {
              childOutput[valueObj._id] = childOutput[valueObj._id] + parseInt(valueObj.value)
            } else {
              childOutput[valueObj._id] = parseInt(valueObj.value)
            }
          });
        });
        return childOutput
      }
      
      function mergeChildNode (inputArray, childOutput) {
        for (const property in childOutput) {
          var isIdPresent = inputArray.filter(e => {
            return  e._id == property
          });
      
          if (isIdPresent.length > 0) {
            var newObj = isIdPresent[0];
            inputArray = inputArray.filter(e => {
              return  e._id != property
            });
            newObj["values"].push(childOutput[property])
            inputArray.push(newObj)
          } else {
            inputArray.push({
              _id: property,
              values: [childOutput[property]]
            })
          }
        }
        return inputArray
      } 

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-12-06
        • 2014-09-13
        • 2018-11-30
        • 2022-01-18
        • 1970-01-01
        • 1970-01-01
        • 2018-02-25
        相关资源
        最近更新 更多