js对象数组属性合并的问题

M酷啊
  • 100

在做一个题目选项的功能时,遇到这个合并的问题,题目有单选和多选,单选没问题,每题就一个答案,多选就会出现多个答案。选择结果类似下图:

图片描述

我需要把同一个多选题的数据合并成一个,就是图中蓝色框选部分的对象合并为一个,option变成"捏,挤",其他的Id不用管。有什么简单的方法实现。跪谢!

回复
阅读 6.6k
3 个回答

一个基本思路,先把数据遍历一遍,相同问题的题目存为一个数组,然后遍历处理相同题目的数组,将答案拼接即可。

示例:
数据:

var questions = [{
    id: Math.random() * 100000 >> 0,
    option: 'x',
    questionId: 1,
    title: '你的名字'
}, {
    id: Math.random() * 100000 >> 0,
    option: '动作1',
    questionId: 2,
    title: '你喜欢的动作'
}, {
    id: Math.random() * 100000 >> 0,
    option: '动作2',
    questionId: 2,
    title: '你喜欢的动作'
}, {
    id: Math.random() * 100000 >> 0,
    option: '动作3',
    questionId: 2,
    title: '你喜欢的动作'
}, {
    id: Math.random() * 100000 >> 0,
    option: '动作4',
    questionId: 2,
    title: '你喜欢的动作'
}, {
    id: Math.random() * 100000 >> 0,
    option: '动作5',
    questionId: 2,
    title: '你喜欢的动作'
}, {
    id: Math.random() * 100000 >> 0,
    option: '歌曲1',
    questionId: 3,
    title: '你喜欢的歌曲'
}, {
    id: Math.random() * 100000 >> 0,
    option: '歌曲2',
    questionId: 3,
    title: '你喜欢的歌曲'
}, {
    id: Math.random() * 100000 >> 0,
    option: '歌曲3',
    questionId: 3,
    title: '你喜欢的歌曲'
}];

// 给相同题目分类

// 给相同题目分类
var categories = {};
questions.forEach(function (item, i) {
    if (!categories[item.questionId]) {
        categories[item.questionId] = [item];
    } else {
        categories[item.questionId].push(item);
    }
});
console.log(JSON.stringify(categories, 0, 2));
// {
//   "1": [
//     {
//       "id": 76350,
//       "option": "x",
//       "questionId": 1,
//       "title": "你的名字"
//     }
//   ],
//   "2": [
//     {
//       "id": 42682,
//       "option": "动作1",
//       "questionId": 2,
//       "title": "你喜欢的动作"
//     },
//     {
//       "id": 19378,
//       "option": "动作2",
//       "questionId": 2,
//       "title": "你喜欢的动作"
//     },
//     {
//       "id": 25613,
//       "option": "动作3",
//       "questionId": 2,
//       "title": "你喜欢的动作"
//     },
//     {
//       "id": 25020,
//       "option": "动作4",
//       "questionId": 2,
//       "title": "你喜欢的动作"
//     },
//     {
//       "id": 70897,
//       "option": "动作5",
//       "questionId": 2,
//       "title": "你喜欢的动作"
//     }
//   ],
//   "3": [
//     {
//       "id": 38775,
//       "option": "歌曲1",
//       "questionId": 3,
//       "title": "你喜欢的歌曲"
//     },
//     {
//       "id": 50039,
//       "option": "歌曲2",
//       "questionId": 3,
//       "title": "你喜欢的歌曲"
//     },
//     {
//       "id": 71712,
//       "option": "歌曲3",
//       "questionId": 3,
//       "title": "你喜欢的歌曲"
//     }
//   ]
// }

对相同类型的题目进行遍历,后面的都放到第一个里面即可。
并重新按照原格式存放

// 用于按照原格式存放最后的数据
var data =[];
for (var key in categories) {
    var i, l;
    if (categories.hasOwnProperty(key)) {
        for (i = 1; i < categories[key].length; ++i) {
            // 第一个的值 = ',' +  下一个的值 
            categories[key][0].option += ',' + categories[key][i].option;
            // 删除下一个
            categories[key].splice(i, 1);
            --i;
        }
        data.push(categories[key][0]);
    }
}
console.log('categories',JSON.stringify(categories, null, 2));
console.log('data',JSON.stringify(data, null, 2));
//  'categories' {
//   "1": [
//     {
//       "id": 72749,
//       "option": "x",
//       "questionId": 1,
//       "title": "你的名字"
//     }
//   ],
//   "2": [
//     {
//       "id": 33498,
//       "option": "动作1,动作2,动作3,动作4,动作5",
//       "questionId": 2,
//       "title": "你喜欢的动作"
//     }
//   ],
//   "3": [
//     {
//       "id": 79801,
//       "option": "歌曲1,歌曲2,歌曲3",
//       "questionId": 3,
//       "title": "你喜欢的歌曲"
//     }
//   ]
// }

// 'data' [
//   {
//     "id": 72749,
//     "option": "x",
//     "questionId": 1,
//     "title": "你的名字"
//   },
//   {
//     "id": 33498,
//     "option": "动作1,动作2,动作3,动作4,动作5",
//     "questionId": 2,
//     "title": "你喜欢的动作"
//   },
//   {
//     "id": 79801,
//     "option": "歌曲1,歌曲2,歌曲3",
//     "questionId": 3,
//     "title": "你喜欢的歌曲"
//   }
// ]

更新

看了2楼的回答,其实之前的过程可以简化,不过确实如3楼所言,和ES6的map没有什么关系。我用了ES5的forEach。不用ES5,只用ES3,换成普通for循环完全没有问题的。使用map反而负复杂了。

由于不需要分类的题目数据,所以可以直接拼接答案,不用先归类了,实现如下:

var data2 = {};
questions.forEach(function (item, i) {
    if (!data2[item.questionId]) {
        data2[item.questionId] = item;
    } else {
        data2[item.questionId].option += ',' + item.option;
    }
});
console.log(JSON.stringify(data2,null,2));
// {
//   "1": {
//     "id": 60348,
//     "option": "x",
//     "questionId": 1,
//     "title": "你的名字"
//   },
//   "2": {
//     "id": 33956,
//     "option": "动作1,动作2,动作3,动作4,动作5",
//     "questionId": 2,
//     "title": "你喜欢的动作"
//   },
//   "3": {
//     "id": 48194,
//     "option": "歌曲1,歌曲2,歌曲3",
//     "questionId": 3,
//     "title": "你喜欢的歌曲"
//   }
// }

这样出来的data2是一个对象的形式,如果需要数组,再处理即可。

还是要赞同三楼的一点。即使是多选题,原数据也不该是你所列的那种组织方式。直接在统计多选题已选答案时就处理好,不是更好的方式吗?

提供一个好玩的思路,能实现,但不一定适用于真实场景;
定义一个空对象,循环遍历数组,然后空对象的属性名为 title对应的值也就是题目; 值为一个数组,把选项push进去,当然这在每一道题中可能还会涉及到去重的问题,最后的结果大概类似这样

obj['动作'] = ['抓','捏']; 

如果可以用es6的话推荐Map

1楼的方法就能解决这个问题,
2楼的map不需要非得es6
3楼拒绝回答这个问题, 因为他觉得这种实现方式不太对

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
宣传栏