0

Consider that I have two arrays as follows:

let a1 = [{id:1, name:'jon'}, {id:2, name:'adam'}]
let a2 = [{id:1, age:42}, {id:2, age:13}]

I want to merge the two arrays so the JSON properties get combined into one array; i.e. this is what I want to end up with:

[{ id: 1, name: 'jon', age: 42 },{ id: 2, name: 'adam', age: 13 }]

Using Ramda I can do the following which gives me close to what I want, but annoyingly it's not in an array - it's all JSON

R.mergeDeepLeft(a1, a2)
{ '0': { id: 1, name: 'yasin', age: 42 },
  '1': { id: 2, name: 'adam', age: 13 } }

5 Answers 5

4

I'd do this:

  1. concat a1 and a2 together. (They don't need to be kept apart)
  2. group objects by id and merge those that share the same id.
  3. finally get all merged objects out.

const res =
  pipe(
    concat,
    reduceBy(mergeLeft, {}, prop('id')),
    values);

console.log(

  res(a1, a2)

);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>
<script>
const {pipe, concat, reduceBy, mergeLeft, values, prop} = R;
const a1 = [{id:1, name:'jon'}, {id:2, name:'adam'}];
const a2 = [{id:1, age:42}, {id:2, age:13}];
</script>

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

2 Comments

Not only a good answer to the question, but one which covers cases where the arrays are in different order, or where either one contains elements not matching any in the other. It also is easily extended to an array of inputs via R.reduce(res, []). Nicely done!
yours is certainly the neatest solution and one I can follow... However, Antons also works, although I'm having difficulty figuring out why!
2

Perhaps not the most elegant nor extensible solution but I'd use some mapping and the spread operator:

let a1 = [{id:1, name:'jon'}, {id:2, name:'adam'}]
let a2 = [{id:1, age:42}, {id:2, age:13}]
let a3 = a1.map(item => {
    return {...item, ...a2.find(item2 => item2.id === item.id)}
})

Here's a working Fiddle for it https://jsfiddle.net/gshfo7pm/

Comments

1

You can use R.values to convert to array, like this:

let a1 = [{id:1, name:'jon'}, {id:2, name:'adam'}]
let a2 = [{id:1, age:42}, {id:2, age:13}]

R.values(R.mergeWith(R.mergeLeft, a1, a2));

If you have unordered arrays, you can do this:

let a1 = [{id:1, name:'jon'}, {id:2, name:'adam'}]
let a2 = [{id:2, age:13}, {id:1, age:42}]

R.values(R.mergeWith(
  R.mergeLeft, 
  R.indexBy(R.prop('id'), a1), 
  R.indexBy(R.prop('id'), a2)
));

1 Comment

Please note that R.merge is deprecated. Also this only works by accident, because the objects in a1 and a2 are nicely lined up. If you swap the objects in a2, {id: 1, name: 'jon'} will be merged with {id:2, age: 13} to give {"age": 13, "id": 2, "name": "jon"}
1

Try this:

let a1 = [{id:1, name:'jon'}, {id:2, name:'adam'}]
let a2 = [{age:13, id:2}, {id:1, age:42}]

const fn = R.pipe(
   R.map(R.indexBy(R.prop('id'))),
   R.reduce(R.mergeWith(R.mergeDeepLeft), {}),
   R.values
)
    
let newArray1 = fn([a1, a2]);
let newArray2 = fn([a2, a1]);
    
console.log(newArray1);
console.log(newArray2);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>

5 Comments

very good, your solution works too with the added benefit that the arrays can be in any order and it will still merge by id.. good jwork
are you sure about that? I tried with swapping the order of a2 and it still worked
i was replying to someone else who said your solution wouldn't work if order switched but it does. the other guy then deleted his comment by the looks of it
Yep that comment was mine. I looked through the revisions of this post and they were all fine. I must have been confused with other answers that were flawed. Since that comment was no longer relevant I deleted it. Also lifted my downvote btw.
Thnx, didn't bother rechecking until @JohnHarrison mentioned it so I added the snippet to be sure.
-1
let concatValues = (k, l, r) =>  r
R.mergeDeepWithKey(concatValues,a1,a2)

will produce this

{"0": {"age": 42, "id": 1, "name": "jon"}, "1": {"age": 13, "id": 2, "name": "adam"}}

it's not exact output but you can start with this

1 Comment

As for some other answers here, this still relies on both a1 and a2 to be sorted by id. If you swap the order of the objects in a2, you end up with an incorrect merge e.g. {"age": 13, "id": 2, "name": "jon"}

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.