简体   繁体   中英

Merge objects with corresponding key values from two different arrays of objects

I've got two arrays that have multiple objects

[
     {
         "name":"paul",
         "employee_id":"8"
     }
]

[
     {
         "years_at_school": 6,
         "department":"Mathematics",
         "e_id":"8"
     }
]

How can I achieve the following with either ES6 or Lodash?

[
     {
         "name":"paul",
         "employee_id":"8"
         "data": {
             "years_at_school": 6
             "department":"Mathematics",
             "e_id":"8"
         }
     }
]

I can merge but I'm not sure how to create a new child object and merge that in.

Code I've tried:

school_data = _.map(array1, function(obj) {
    return _.merge(obj, _.find(array2, {employee_id: obj.e_id}))
})

This merges to a top level array like so (which is not what I want):

{
     "name":"paul",
     "employee_id":"8"
     "years_at_school": 6
     "department":"Mathematics",
     "e_id":"8"
 }

The connector between these two is "employee_id" and "e_id" .

It's imperative that it's taken into account that they could be 1000 objects in each array, and that the only way to match these objects up is by "employee_id" and "e_id" .

In order to match up employee_id and e_id you should iterate through the first array and create an object keyed to employee_id . Then you can iterate though the second array and add the data to the particular id in question. Here's an example with an extra item added to each array:

 let arr1 = [ { "name":"mark", "employee_id":"6" }, { "name":"paul", "employee_id":"8" } ] let arr2 = [ { "years_at_school": 6, "department":"Mathematics", "e_id":"8" }, { "years_at_school": 12, "department":"Arr", "e_id":"6" } ] // empObj will be keyed to item.employee_id let empObj = arr1.reduce((obj, item) => { obj[item.employee_id] = item return obj }, {}) // now lookup up id and add data for each object in arr2 arr2.forEach(item=> empObj[item.e_id].data = item ) // The values of the object will be an array of your data let merged = Object.values(empObj) console.log(merged) 

If you perform two nested O(n) loops (map+find), you'll end up with O(n^2) performance. A typical alternative is to create intermediate indexed structures so the whole thing is O(n). A functional approach with lodash:

const _ = require('lodash');
const dataByEmployeeId = _(array2).keyBy('e_id');
const result = array1.map(o => ({...o, data: dataByEmployeeId.get(o.employee_id)}));

Hope this help you:

 var mainData = [{ name: "paul", employee_id: "8" }]; var secondaryData = [{ years_at_school: 6, department: "Mathematics", e_id: "8" }]; var finalData = mainData.map(function(person, index) { person.data = secondaryData[index]; return person; }); 

Sorry, I've also fixed a missing coma in the second object and changed some other stuff.

With latest Ecmascript versions:

 const mainData = [{ name: "paul", employee_id: "8" }]; const secondaryData = [{ years_at_school: 6, department: "Mathematics", e_id: "8" }]; // Be careful with spread operator over objects.. it lacks of browser support yet! ..but works fine on latest Chrome version for example (69.0) const finalData = mainData.map((person, index) => ({ ...person, data: secondaryData[index] })); 

A slightly different approach just using vanilla js map with a loop to match the employee ids and add the data from the second array to the matching object from the first array. My guess is that the answer from @MarkMeyer is probably faster.

 let arr1 = [{ "name": "paul", "employee_id": "8" }] let arr2 = [{ "years_at_school": 6, "department": "Mathematics", "e_id": "8" }] let results = arr1.map(obj1 => { for (let obj2 of arr2) { if (obj2.e_id === obj1.employee_id) { obj1.data = obj2; break; } } return obj1; }); console.log(results); 

Your question suggests that both arrays will always have the same size. It also suggests that you want to put the contents of array2 within the field data of the elements with the same index in array1 . If those assumptions are correct, then:

// Array that will receive the extra data
const teachers = [
    { name: "Paul", employee_id: 8 },
    { name: "Mariah", employee_id: 10 }
];

// Array with the additional data
const extraData = [
    { years_at_school: 6, department: "Mathematics", e_id: 8 },
    { years_at_school: 8, department: "Biology", e_id: 10 },
];

// Array.map will iterate through all indices, and gives both the
const merged = teachers.map((teacher, index) => Object.assign({ data: extraData[index] }, teacher));

However, if you want the data to be added to the employee with an "id" matching in both arrays, you need to do the following:

// Create a function to obtain the employee from an ID
const findEmployee = id => extraData.filter(entry => entry.e_id == id);

merged = teachers.map(teacher => {
    const employeeData = findEmployee(teacher.employee_id);

    if (employeeData.length === 0) {
        // Employee not found
        throw new Error("Data inconsistency");
    }

    if (employeeData.length > 1) {
        // More than one employee found
        throw new Error("Data inconsistency");
    }

    return Object.assign({ data: employeeData[0] }, teacher);
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM