2

I have two arrays, which look like this:

const persons = [
  {
    id: 1,
    name: 'Peter',
    job: 'Programmer'
  },
  {
    id: 2,
    name: 'Jeff',
    job: 'Architect'
  },
];

const salaries = [
  {
    id: 1,
    salary: 3000,
    departments: ['A', 'B'] 
  },
  {
    id: 1,
    salary: 4000,
    departments: ['A', 'C']
  },
  {
    id: 2,
    salary: 4000,
    departments: ['C', 'D']
  }
];

Now I need to somehow merge this arrays to one, so that every id only exists once. Same keys should be replaced, except it is an array, then I want them to add/concat. So the desired result should look something like this:

const result = [
  {
    id: 1,
    name: 'Peter',
    job: 'Programmer',
    salary: 4000,
    departments: ['A', 'B', 'C'] 
  },
  {
    id: 2,
    name: 'Jeff',
    job: 'Architect',
    salary: 4000,
    departments: ['C', 'D']
  }
];

I have already tried:

// double id's, arrays get replaced
Object.assign({}, persons, salaries)

// loadsh: double id's, arrays get concatenated
_.mergeWith(persons, salaries, (objValue, srcValue) => {
    if (_.isArray(objValue)) {
        return objValue.concat(srcValue);
    }
});

// gives me a map but replaces arrays
new Map(salaries.map(x => [x.id, x])

Does anyone have an idea how to accomplish this?

3
  • I'll give you a hint sort both the arrays with respect to id and then try to compare em Commented Apr 4, 2018 at 11:04
  • what's the logic to understand which of the salary should be taken? the latest? the highest salary? Commented Apr 4, 2018 at 11:12
  • @MiguelAngel the latest Commented Apr 4, 2018 at 11:14

3 Answers 3

2

You can use map(), filter(), reduce(), Object.assign() and Spread syntax to achieve required result.

DEMO

const persons = [{
    id: 1,
    name: 'Peter',
    job: 'Programmer'
  }, {
    id: 2,
    name: 'Jeff',
    job: 'Architect'
  }],
  salaries = [{
    id: 1,
    salary: 3000,
    departments: ['A', 'B']
  }, {
    id: 1,
    salary: 4000,
    departments: ['A', 'C']
  }, {
    id: 2,
    salary: 4000,
    departments: ['C', 'D']
  }];


let output = persons.map(obj => {
  let filter = salaries.filter(v => v.id == obj.id);
  if (filter) {
    let departments = filter.reduce((r, v) => [...v.departments, ...r], []);
    Object.assign(obj, {
      salary: filter[filter.length - 1].salary,
      departments: departments.filter((item, pos) => departments.indexOf(item) == pos).sort()
    });
  }
  return obj;
});

console.log(output)

Sign up to request clarification or add additional context in comments.

1 Comment

would you be able to help me with stackoverflow.com/questions/60222532/…?
1

You can concat the arrays, than combine all items with the same id using Array.reduce(), and a Map.

to combine objects with the same id, get the object from the Map. Iterate the new Object.entries() with Array.forEach(). Check if existing value is an array, if not assign the value. If it is an array, combine the arrays, and make the items unique using a Set with array spread.

To convert the Map back to an array, you can spread the Map.values() iterator.

const persons = [{"id":1,"name":"Peter","job":"Programmer"},{"id":2,"name":"Jeff","job":"Architect"}];
const salaries = [{"id":1,"salary":3000,"departments":["A","B"]},{"id":1,"salary":4000,"departments":["A","C"]},{"id":2,"salary":4000,"departments":["C","D"]}];

const result = [...persons.concat(salaries)
  .reduce((r, o) => {
    r.has(o.id) || r.set(o.id, {});
    
    const item = r.get(o.id);
    
    Object.entries(o).forEach(([k, v]) =>
      item[k] = Array.isArray(item[k]) ? 
        [...new Set([...item[k], ...v])] : v
    );
    
    return r;
  }, new Map()).values()];
  
console.log(result);

Comments

1

You could use a Map and iterate all properties and check the type for adding unique values to the arrays.

var persons = [{ id: 1, name: 'Peter', job: 'Programmer' }, { id: 2, name: 'Jeff', job: 'Architect' }],
    salaries = [{ id: 1, salary: 3000, departments: ['A', 'B'] }, { id: 1, salary: 4000, departments: ['A', 'C'] }, { id: 2, salary: 4000, departments: ['C', 'D'] }],
    result = Array.from(
        salaries
            .reduce(
                (m, o) => {
                    var t = m.get(o.id) || {};
                    Object.keys(o).forEach(k => {
                        if (Array.isArray(o[k])) {
                            t[k] = t[k] || [];
                            o[k].forEach(v => t[k].includes(v) || t[k].push(v));
                        } else if (t[k] !== o[k]) {
                            t[k] = o[k];
                        }
                    });
                    return m;
                },
                persons.reduce((m, o) => m.set(o.id, Object.assign({}, o)), new Map)
            )
            .values()
    );

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.