嵌套对象数组分组

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"
                    }
                ]
            }
        ]
    },
];

我希望能够根据属性 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 ='a'的属性中_id='aa'的值中。


预期输出不清楚。 - brk
@brk 请看我的编辑,我添加了一个解释。 - Ayoub k
3个回答

2

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)


1
使用更直接/本地的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);

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"
                  }
              ]
          }
      ]
  },
];

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
} 


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