基于Javascript中的公共值合并同一数组中的对象

时间:2017-05-02 15:37:12

标签: javascript arrays lodash

我有一个数组:

[
  {
    assignmentId:17,
    email:"john.smith@email.com"
    expectation: "Make sure to proofread!",
    firstName:"John"
    id:23
    ignoreForFeedback: true
    lastName:"Smith"
    level:2
    levelFraction:null
    score:35
  },
  {
    assignmentId:17
    countsPerCategory: Array(4)
    email:"john.smith@email.com"
    firstName:"John"
    frequentErrors: Array(5)
    id:23
    ignoreForGrading: true
    lastName:"Smith"
  },
  {
    assignmentId:17,
    email:"cl@email.com"
    expectation: "cite sources",
    firstName:"Cindy"
    id:45
    ignoreForFeedback: true
    lastName:"Lee"
    level:2
    levelFraction:null
    score:32
  },
  {
    assignmentId:17
    countsPerCategory: Array(4)
    email:"cl@email.com"
    firstName:"Cindy"
    frequentErrors: Array(5)
    id:45
    ignoreForGrading: true
    lastName:"Lee"
  }
]

我想将对象与相同的&id;#id;进入数组中的同一个对象。他们的共同键也应该组合在一起(例如:' firstName',' email')。有人可以建议最好的方法吗?使用ES6或Lodash

4 个答案:

答案 0 :(得分:4)

您可以使用lodash#groupByid对数组中的所有项目进行分组,然后使用lodash#map,其lodash#assign的迭代包含lodash#spread将数组回调作为lodash#assgin的参数列表。

var result = _(array)
  .groupBy('id')
  .map(_.spread(_.assign))
  .value();



var array = [
  {
    assignmentId:17,
    email:"john.smith@email.com",
    expectation: "Make sure to proofread!",
    firstName:"John",
    id:23,
    ignoreForFeedback: true,
    lastName:"Smith",
    level:2,
    levelFraction:null,
    score:35
  },
  {
    assignmentId:17,
    countsPerCategory: Array(4),
    email:"john.smith@email.com",
    firstName:"John",
    frequentErrors: Array(5),
    id:23,
    ignoreForGrading: true,
    lastName:"Smith"
  },
  {
    assignmentId:17,
    email:"cl@email.com",
    expectation: "cite sources",
    firstName:"Cindy",
    id:45,
    ignoreForFeedback: true,
    lastName:"Lee",
    level:2,
    levelFraction:null,
    score:32
  },
  {
    assignmentId:17,
    countsPerCategory: Array(4),
    email:"cl@email.com",
    firstName:"Cindy",
    frequentErrors: Array(5),
    id:45,
    ignoreForGrading: true,
    lastName:"Lee"
  }
];

var result = _(array)
  .groupBy('id')
  .map(_.spread(_.assign))
  .value();
  
console.log(result);

body > div { min-height: 100%; top: 0; }

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>
&#13;
&#13;
&#13;

这是一个使用Array#filter的替代解决方案,它利用了Array#filter的第二个参数,它为过滤器的回调函数提供了上下文。我们使用this上下文作为一种机制来存储缓存对象的id,然后使用它来决定是否从数组中保留这些对象。

var result = array.filter(function(v) {
  return this[v.id]?
    !Object.assign(this[v.id], v):
    (this[v.id] = v);
}, {});

&#13;
&#13;
var array = [
  {
    assignmentId:17,
    email:"john.smith@email.com",
    expectation: "Make sure to proofread!",
    firstName:"John",
    id:23,
    ignoreForFeedback: true,
    lastName:"Smith",
    level:2,
    levelFraction:null,
    score:35
  },
  {
    assignmentId:17,
    countsPerCategory: Array(4),
    email:"john.smith@email.com",
    firstName:"John",
    frequentErrors: Array(5),
    id:23,
    ignoreForGrading: true,
    lastName:"Smith"
  },
  {
    assignmentId:17,
    email:"cl@email.com",
    expectation: "cite sources",
    firstName:"Cindy",
    id:45,
    ignoreForFeedback: true,
    lastName:"Lee",
    level:2,
    levelFraction:null,
    score:32
  },
  {
    assignmentId:17,
    countsPerCategory: Array(4),
    email:"cl@email.com",
    firstName:"Cindy",
    frequentErrors: Array(5),
    id:45,
    ignoreForGrading: true,
    lastName:"Lee"
  }
];

var result = array.filter(function(v) {

  // does this `id` exist?
  return this[v.id]? 
  
    // assign existing object with the same id
    // from the `this` cache object. Make sure
    // to negate the resulting object with a `!`
    // to remove this value from the array
    !Object.assign(this[v.id], v):
    
    // Assign the value from the `this` cache.
    // This also retains this value from the existing
    // array
    (this[v.id] = v);
    
}, {});

console.log(result);
&#13;
body > div { min-height: 100%; top: 0; }
&#13;
&#13;
&#13;

答案 1 :(得分:1)

您可以使用JavaScript内置的Array.reduce()方法。我们的想法是,您可以使用ID创建地图,并使用lodash.merge()方法(或您选择用于合并对象的任何方法)将具有相同ID的所有对象合并到单个对象中。然后,您可以在创建的.map()上使用idMap将对象恢复为单个数组。

    var data = [{
        assignmentId: 17,
        email: "john.smith@email.com",
        expectation: "Make sure to proofread!",
        firstName: "John",
        id: 23,
        ignoreForFeedback: true,
        lastName: "Smith",
        level: 2,
        levelFraction: null,
        score: 35
      },
      {
        assignmentId: 17,
        countsPerCategory: Array(4),
        email: "john.smith@email.com",
        firstName: "John",
        frequentErrors: Array(5),
        id: 23,
        ignoreForGrading: true,
        lastName: "Smith"
      },
      {
        assignmentId: 17,
        email: "cl@email.com",
        expectation: "cite sources",
        firstName: "Cindy",
        id: 45,
        ignoreForFeedback: true,
        lastName: "Lee",
        level: 2,
        levelFraction: null,
        score: 32
      },
      {
        assignmentId: 17,
        countsPerCategory: Array(4),
        email: "cl@email.com",
        firstName: "Cindy",
        frequentErrors: Array(5),
        id: 45,
        ignoreForGrading: true,
        lastName: "Lee"
      }
    ];

    var idMap = data.reduce(function(result, current) {
      if (result[current.id] == null) {
        result[current.id] = current;
      } else {
        _.merge(result[current.id], current);
      }

      return result;
    }, {});

    var results = Object.keys(idMap).map(function(key) {
      return idMap[key];
    });

    console.log(results);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>

答案 2 :(得分:1)

我可以建议使用forEach()some()方法的组合来迭代数组元素并测试迭代对象id是否已经处理过。

这是解决方案:

var merged = [];

arr.forEach(function(item) {
  var idx;
  var found = merged.some(function(el, i) {
    idx = el.id === item.id ? i : null;
    return el.id === item.id;
  });
  if (!found) {
    merged.push(item);
  } else if (idx !== null) {
    for (k in Object.keys(item)) {
      if (item.hasOwnProperty(k)) {
        merged[idx][k] = item[k];
      }
    }
  }
});

工作演示:

var arr = [{
    assignmentId: 17,
    email: "john.smith@email.com",
    expectation: "Make sure to proofread!",
    firstName: "John",
    id: 23,
    ignoreForFeedback: true,
    lastName: "Smith",
    level: 2,
    levelFraction: null,
    score: 35
  },
  {
    assignmentId: 17,
    countsPerCategory: [],
    email: "john.smith@email.com",
    firstName: "John",
    frequentErrors: [],
    id: 23,
    ignoreForGrading: true,
    lastName: "Smith"
  },
  {
    assignmentId: 17,
    email: "cl@email.com",
    expectation: "cite sources",
    firstName: "Cindy",
    id: 45,
    ignoreForFeedback: true,
    lastName: "Lee",
    level: 2,
    levelFraction: null,
    score: 32
  },
  {
    assignmentId: 17,
    countsPerCategory: [],
    email: "cl@email.com",
    firstName: "Cindy",
    frequentErrors: [],
    id: 45,
    ignoreForGrading: true,
    lastName: "Lee"
  }
];
var merged = [];

arr.forEach(function(item) {
  var idx;
  var found = merged.some(function(el, i) {
    idx = el.id === item.id ? i : null;
    return el.id === item.id;
  });
  if (!found) {
    merged.push(item);
  } else if (idx !== null) {
    for (k in Object.keys(item)) {
      if (item.hasOwnProperty(k)) {
        merged[idx][k] = item[k];
      }
    }
  }
});
console.log(merged);

答案 3 :(得分:0)

感谢大家的帮助,但我最终选择了自己的实施方式。

        let ids = [];
        let combinedUsers = [];

        users.forEach(function (user) {
            ids.push(user.id);
        });

        ids = _.uniq(ids);
        ids.forEach(function(id){
            let user = users.filter(function(userObj){
                return id === userObj.id
            });

            if(user.length > 1){
                user = Object.assign(user[0], user[1]);
                combinedUsers.push(user);
            } else {
                combinedUsers.push(user[0]);
            }

        });
        return combinedStudents;