数据格式的转换问题

问题描述

  const data = [
    {
      month:'2019-01',
      list:[
        {name:'语文',share:98},
        {name:'数学',share:89},
        {name:'其它',share:45},
      ]
    },
    {
      month:'2019-02',
      list:[
        {name:'外语',share:34},
        {name:'数学',share:56},
        {name:'其它',share:33},
      ]
    }
  ]  

转换成

[
  ['month','2019-01','2019-02'],
  ['语文',98,0],
  ['数学',89,56],
  ['外语',0,34],
  ['其它',45,33],
]

问题出现的环境背景及自己尝试过哪些方法

相关代码

// 请把代码文本粘贴到下方(请勿用图片代替代码)
我考虑先把所有科目都找出来

  // 取出所有类目
  const ALL = [
    ...new Set(
      monthList &&
        monthList
          .map(i => i.list)
          .flat(1)
          .map(j => j.name)
    ),
  ];

想的是
ALL.map()结果发现至少要map三层 复杂度很高
有没有算法简单点的处理方式

阅读 3.5k
7 个回答
const data = [];  //原数据

const result = data.reduce(({months, names}, {month, list}, index) => {
  months.push(month);
  list.forEach(v => {
    if (!names[v.name]) names[v.name] = {};
    names[v.name][month] = v.share;
  });
  if (index === data.length - 1) {
    return [
      ['month', ...months],
      ...Object.keys(names).map(name => [
        name, ...months.map(_month => names[name][_month] || 0),
      ]),
    ];
  }
  return {months, names};
}, {months: [], names: {}});

console.log(result);

写完发现这个解决方式复杂度还是挺高的,应该还有更优解


再提供一个解决方式,先提取names,逻辑简单得多

const result = data.reduce((ary, {month, list}) => {
  ary.forEach((arr, i) => {
    let v = i ? list.find(v => v.name === arr[0]) : month;
    arr.push(i ? (v ? v.share : 0) : v);
  });
  return ary;
}, [...new Set(['month', ...data.flatMap(v => v.list.map(v => v.name))])].map(v => [v]));

数据层次嵌套较深,应该是至少需要三层循环的,find也是一层。。。坐等大佬的简便方法

const data = [
    {
        month:'2019-01',
        list:[
            {name:'语文',share:98},
            {name:'数学',share:89},
            {name:'其它',share:45},
        ]
    },
    {
        month:'2019-02',
        list:[
            {name:'外语',share:34},
            {name:'数学',share:56},
            {name:'其它',share:33},
        ]
    }
]
let arr = [
    ['month']
]
data.forEach(month => {
    arr[0].push(month.month)
    month.list.forEach((name,index) => {
        let find = arr.find(find => find[0] == name.name)
        find ? find.push(name.share) : arr.push([name.name, name.share])
    })
})
console.log(arr)
  const temp = {
      0:['语文'],
      1:['数学'],
      2:['其他']
  }
  const mArr = ['month']
  data.forEach(d=>{
    mArr.push(d.month)
    d.list.forEach((l,i)=>{
        temp[i].push(l.share)
    })
  })

  let res = [mArr,temp[0], temp[1], temp[2]]
const data = [
  {
    month: '2019-01',
    list: [
      { name: '语文', share: 98 },
      { name: '数学', share: 89 },
      { name: '其它', share: 45 }
    ]
  },
  {
    month: '2019-02',
    list: [
      { name: '外语', share: 34 },
      { name: '数学', share: 56 },
      { name: '其它', share: 33 }
    ]
  }
]

function trans (data) {
  const r = data.reduce((res, val, i) => {
    res[0].push(val.month)
    val.list.forEach(s => {
      res[1][s.name] = res[1][s.name] || []
      res[1][s.name][i] = s.share
      let j = i - 1
      while (!res[1][s.name][j] && j > -1) {
        res[1][s.name][j--] = 0
      }
    })
    return res
  }, [['month'], {}])
  return [r[0], ...Object.entries(r[1]).map(val => [val[0], ...val[1], ...new Array(r[0].length - val[1].length - 1).fill(0)])]
}

console.log(trans(data))
// [ [ 'month', '2019-01', '2019-02' ],
//   [ '语文', 98, 0 ],
//   [ '数学', 89, 56 ],
//   [ '其它', 45, 33 ],
//   [ '外语', 0, 34 ] ]

写完发现好蛋疼

个人理解的写法,示例如下,可以参考

const data = [
  {
    month:'2019-01',
    list:[
      {name:'语文',share:98},
      {name:'数学',share:89},
      {name:'其它',share:45},
    ]
  },
  {
    month:'2019-02',
    list:[
      {name:'语文',share:34},
      {name:'外语',share:34},
      {name:'数学',share:56},
      {name:'其它',share:33},
    ]
  }
] 

let monthArray = ['month'];

let objAll = {
  '语文':['语文'],
  '数学':['数学'],
  '外语':['外语'],
  '其它':['其它']
}

data.map((item,index)=>{
  let {list} = item;
  monthArray.push(item.month);
  list.map(obj=>{
    let {name,share} = obj;
    objAll[name].push(share);
  })
  for(let key in objAll){
    if(objAll[key].length==index+1){
      objAll[key].push(0)
    }
  }
})

let success = [
  monthArray
]

for(let key in objAll){
  success.push(objAll[key])
}
console.log(success)

输出截图:

图片描述

function zip(arr) {
    var ret = [];
    if (arr instanceof Array) {
        var obj = {};
        for (var i = 0; i < arr.length; ++i) {
            (obj.month || (obj.month = [])).push(arr[i].month);
            for (var j = 0; j < arr[i].list.length; ++j) {
                arr[i].list[j].name in obj || (obj[arr[i].list[j].name] = []);
                obj[arr[i].list[j].name][i] = arr[i].list[j].share;
            }
        }
        for (var key in obj) {
            for (var i = 0; i < obj.month.length && key !== "month"; ++i) {
                obj[key][i] == null && (obj[key][i] = 0);
            }
            ret.push([key].concat(obj[key]));
        }
    }
    return ret;
}
console.log(zip(data));

至少三层循环。
第一次是data对象的循环;第二次是data.list的循环;
第三次是结果变为数组的循环,无论对象转数组,还是直接在数组找键,都必须经历一次;

下面虽然是三层循环,但是是单链的。一次执行完毕,没有嵌套循环。执行次数由data的数据数量及最后结果项的数组大小决定。

const data = [
  {
    month: "2019-01",
    list: [
      { name: "语文", share: 98 },
      { name: "数学", share: 89 },
      { name: "其它", share: 45 }
    ]
  },
  {
    month: "2019-02",
    list: [
      { name: "外语", share: 34 },
      { name: "数学", share: 56 },
      { name: "其它", share: 33 }
    ]
  }
];

const hash = {};

for (let i = 0, n = data.length; n > i; ) {
  const {
    [i++]: { list, month }
  } = data;

  (hash.month || (hash.month = ["month"]))[i] = month;
  for (const { name, share } of list) {
    (hash[name] || (hash[name] = [name].concat(new Array(n).fill(0))))[
      i
    ] = share;
  }
}

console.log(Object.values(hash));
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题