使用Javascript将对象数组映射为非重复值对象

时间:2018-07-02 13:24:37

标签: javascript arrays object filter

我试图找到一种方法来转换JS对象上的主题列表,以便创建一个没有重复值的过滤器。

到目前为止,我设法将唯一值映射并过滤到两个单独的数组中。我设法编写的代码是基本代码(不能解决问题):

var topic = subject
           .map(function (value) { return value.topic })
           .filter(function (elem, index, self) {
             return index == self.indexOf(elem);
           });

所以我的主体形状如下:

var subjects = [ {
  "topic" : "Social Sciences",
  "subtopic" : "Developmental Issues"
}, {
  "topic" : "Social Sciences",
  "subtopic" : "General"
}, {
  "topic" : "Social Sciences",
  "subtopic" : "General"
}, {
  "topic" : "Social Sciences",
  "subtopic" : "General and Others"
},{
  "topic" : "Social Sciences",
  "subtopic" : "Arts"
},{
  "topic" : "Social Sciences",
  "subtopic" : "History"
}, {
  "topic" : "Arts and Humanities",
  "subtopic" : "History"
}, {
  "topic" : "Arts and Humanities",
  "subtopic" : "Literature"
} ]

我需要创建一个看起来像这样的过滤器:

 filter = [{
         name: "Social Sciences",
         {
             subtopic: "Developmental Issues",
             subtopic: "General",
             subtopic: "General and Others",
             subtopic: "Arts",
             subtopic: "History"
         }
     }, {
         name: "Arts and Humanities",
         {
             subtopic: "History",
             subtopic: "Literature"
         }
     }

4 个答案:

答案 0 :(得分:0)

对象键应该是唯一的。一个对象中不能有多个具有相同名称的键。一种选择是将数组用于subtopic

使用reduce将数组分组为一个对象。将new Set()用于子主题可获取唯一值。使用Object.values将对象转换为数组。

map数组,并使用扩展语法将集合转换为数组。

var subjects = [{"topic":"Social Sciences","subtopic":"Developmental Issues"},{"topic":"Social Sciences","subtopic":"General"},{"topic":"Social Sciences","subtopic":"General"},{"topic":"Social Sciences","subtopic":"General and Others"},{"topic":"Social Sciences","subtopic":"Arts"},{"topic":"Social Sciences","subtopic":"History"},{"topic":"Arts and Humanities","subtopic":"History"},{"topic":"Arts and Humanities","subtopic":"Literature"}];

var filter = Object.values(subjects.reduce((c, v) => {
  c[v.topic] = c[v.topic] || {name: v.topic,subtopic: new Set()};
  c[v.topic].subtopic.add(v.subtopic);
  return c;
}, {})).map(o => {
  o.subtopic = [...o.subtopic];
  return o;
})

console.log(filter);

答案 1 :(得分:0)

您不能在一个对象中多次使用相同的键,因此您可以为subtopic创建一个数组结构,然后使用subtopic将匹配的reduce推入那里:

var subjects = [ {
  "topic" : "Social Sciences",
  "subtopic" : "Developmental Issues"
}, {
  "topic" : "Social Sciences",
  "subtopic" : "General"
}, {
  "topic" : "Social Sciences",
  "subtopic" : "General"
}, {
  "topic" : "Social Sciences",
  "subtopic" : "General and Others"
},{
  "topic" : "Social Sciences",
  "subtopic" : "Arts"
},{
  "topic" : "Social Sciences",
  "subtopic" : "History"
}, {
  "topic" : "Arts and Humanities",
  "subtopic" : "History"
}, {
  "topic" : "Arts and Humanities",
  "subtopic" : "Literature"
} ];

var filter = subjects.reduce(function(acc, subject){
  var accTopic = acc.find(item => item.name === subject.topic);
  if(!accTopic){
    acc.push({'name': subject.topic, 'subtopic': [subject.subtopic]});
    return acc;
 } else {
   accTopic.subtopic.push(subject.subtopic);
   return acc;
 }
},[]);
console.log(filter);

答案 2 :(得分:0)

let res = subjects.reduce((acc, v, i) => {
    let topic = acc.find(item => item.name == v.topic)
    if (! topic) {
        topic = {name: v.topic, subtopics: []}
        acc.push(topic)
    }
    topic.subtopics.push(v.subtopic)
    return acc
}, [])

否则,您不能在同一个对象上使用相同的键,如果可以帮助您,则我用一个子主题组成一个数组。

答案 3 :(得分:0)

使用Array.prototype.reduce按主题对数据进行分组,然后使用Object.keysArray.prototype.map进行映射:

NOTE:子主题的输出是Array而不是Object,因为对象的相同键将被覆盖。

var subjects = [{"topic":"Social Sciences","subtopic":"Developmental Issues"},{"topic":"Social Sciences","subtopic":"General"},{"topic":"Social Sciences","subtopic":"General"},{"topic":"Social Sciences","subtopic":"General and Others"},{"topic":"Social Sciences","subtopic":"Arts"},{"topic":"Social Sciences","subtopic":"History"},{"topic":"Arts and Humanities","subtopic":"History"},{"topic":"Arts and Humanities","subtopic":"Literature"}];

var datObj = subjects.reduce((all, {topic, subtopic}) => {
  if (!all.hasOwnProperty(topic)) all[topic] = [];
  all[topic].push(subtopic);
  return all;
}, {});

var filter = Object.keys(datObj).map(topic => ({name: topic, subtopic: datObj[topic]}))

console.log(filter);