如何将对象转换为嵌套对象

时间:2019-06-20 12:11:36

标签: javascript arrays

我是JavaScript和编程新手。我通过AJAX获取数据。我想重新生成它,以得到按数据部分分组的嵌套对象。在这种情况下,我希望按yearmonth分组

这是我的数据和功能:

myObj = [
    	  {"date":'2019-06-05',"name":"abc 0"},
    	  {"date":'2019-06-01',"name":"abc 1"},
    	  {"date":'2019-05-25',"name":"abc 2"},
    	  {"date":'2019-05-15',"name":"abc 3"},
    	  {"date":'2020-06-30',"name":"abc 4"},
    	  {"date":'2020-06-25',"name":"abc 5"},
    	  {"date":'2020-05-28',"name":"abc 6"},
    	  {"date":'2020-05-26',"name":"abc 7"}
            ];

function regenerate(data) {
  var result = {
    "allyears": [{}]
  };
  for (x = 0; x < data.length; x++) {
    var year = data[x].date.slice(0, 4);
    var month = data[x].date.slice(5, 7);

    if (!result.allyears.months) {
      result.allyears['year'] = year;
      result.allyears.months = [{}];
    }
    if (!result.allyears.months.data) {
      result.allyears.months['month'] = month;
      result.allyears.months.data = [{}];
    }
    result.allyears.months.data[x] = data[x];
  }
  console.log(result);
  return result;
};

regenerate(myObj);

我期望的结果:

{
  "allyears": [{
    "year": "2019",
    "months": [{
      "month": "06",
      "data": [{
          "date": '2019-06-05',
          "name": "abc 0"
        },
        {
          "date": '2019-06-01',
          "name": "abc 1"
        }
      ]
    }, {
      "month": "05",
      "data": [{
          "date": '2019-05-25',
          "name": "abc 2"
        },
        {
          "date": '2019-05-15',
          "name": "abc 3"
        },
      ]
    }]
  }]
};

我的功能中缺少什么?

1 个答案:

答案 0 :(得分:1)

可能不是最聪明的解决方案,但它应该“漂亮”地完成工作。 该例程利用Array.reduce的优势,其中使用了初始累加器(在这种情况下为空数组),并且在循环原始myObj数组时,它检查是否:

  • 年份元素存在于数组中。如果没有,它将创建它。
  • month元素存在于year元素中。如果没有,它将创建它。
  • 创建所有内容后,它会将数据添加到当月。

我将在下面的代码片段中添加一些注释以进行进一步的解释,对我来说输出似乎还可以。

const myObj = [
      {"date":'2019-06-05',"name":"abc 0"},
      {"date":'2019-06-01',"name":"abc 1"},
      {"date":'2019-05-25',"name":"abc 2"},
      {"date":'2019-05-15',"name":"abc 3"},
      {"date":'2020-06-30',"name":"abc 4"},
      {"date":'2020-06-25',"name":"abc 5"},
      {"date":'2020-05-28',"name":"abc 6"},
      {"date":'2020-05-26',"name":"abc 7"}
];

let res = {
  allyears: myObj.reduce((acc, next) => {
    let [year, month, day] = next.date.split('-');
    // ^-- Acquire year, month and day (actually, day is not needed) from the original date string.
    let yearRef = acc.find(i => i.year === year);
    // ^-- checks whether the current year already exists in the array.
    if (!yearRef) acc.push({year}), yearRef = acc[acc.length - 1];
    // ^-- if it doesn't, it creates it and fill the above reference of it.
    yearRef.months = yearRef.months || [];
    // ^-- same as the year above, but with month.
    let monthRef = yearRef.months.find(i => i.month === month);
    if (!monthRef) yearRef.months.push({month}), monthRef = yearRef.months[yearRef.months.length - 1]// ^-- same as above, with month.
    monthRef.data = (monthRef.data || []).concat(next);
    // ^-- once the month element is available, add the next element to data. If data does not yet exist, init it.
    return acc;
  }, [])
};

console.log(res);