In previous posts, we’ve seen how to create a new List, and how to add, insert and delete items. Now it’s time to get a bit more advanced and look at the ways you can merge two or more Lists together.

Note: Remember that Immutable does not alter any of the Lists being merged. The merged List is always returned from any merge function, leaving any List involved in the merge operation entirely unchanged. Accordingly, whenever you see phrases such as ‘merges Lists together…’ or ‘overwrites originalList’, it’s the copy of the Lists involved that’s being mutated (and ultimately returned as the merged List).

A List’s Four Merge functions

Immutable provides four separate merge functions:

  • originalList.merge(List1, List2, List3...List-n) – merges Lists together by overwriting each item of originalList with the item in List1 (and List2, List3…List-n) at the corresponding position.
  • mergeWith(conflictResolutionFn, List1, List2, List3...List-n) – merges Lists together, but uses the passed-in conflictResolutionFn() to resolve any conflicts
  • mergeDeep(List1, List2, List3...List-n) – merges Lists together, and if a conflict exists, it merges the conflicting items anyway
  • mergeDeepWith(conflictResolutionFn, List1, List2, List3...List-n) – merges Lists together, and if a conflict exists, it uses the passed-in conflictResolutionFn() to resolve it.

Here’s how to use these functions.

merge()

Merge two Lists together

merge() overwrites the value of each item in a List with the value in the merging List that exists at the corresponding index.


// Merge two lists together with merge

const oldAvengers = Immutable.List(['ironMan', 'captainAmerica', 'theHulk']);
const newAvengers = Immutable.List(['scarletWitch', 'vision']);

// Merge all the lists!
oldAvengers.merge(newAvengers);

Confused? Here’s what’s happening:

  • The value of oldAvengers[0] = 'ironMan'
  • The value of newAvengers[0] = 'scarletWitch'
  • The value of each item in a List (i.e. oldAvengers) is overwritten by the value in the merging List (i.e. newAvengers) at the corresponding index (i.e. index 0).
  • So, ‘scarletWitch’ (the value at newAvengers[0]) overwrites ‘ironMan’ (the value at oldAvengers[0]); ‘vision’ overwrites ‘captainAmerica’; but newAvengers[2] doesn’t exist, so oldAvengers[2] (i.e. ‘theHulk’) remains unchanged.

Merge more than two Lists together

When you merge more than two Lists together, the Lists will be merged in turn, with the last List ultimately overwriting all previous Lists.


// Merge more than one List together

const oldAvengers = Immutable.List(['ironMan', 'captainAmerica', 'theHulk']);
const newAvengers = Immutable.List(['scarletWitch', 'vision']);
const newerAvengers = Immutable.List(['antMan']);

// Merge all the lists!
oldAvengers.merge(newAvengers, newerAvengers);


mergeWith()

mergeWith() lets you provide your own conflict resolution function, so you can make the merge more intelligent than just overwriting by index value, and more specific to your needs. You use it like so:

list1.mergeWith(conflictResolutionFn(list1Value, list2Value, index){}, list2)

Here are some examples:

Merge lists and resolve conflicts according to item value


// Merge lists only if item is not null with mergeWith()

const oldAvengers = Immutable.List(['ironMan', 'captainAmerica', 'theHulk']);
const newAvengers = Immutable.List(['scarletWitch', null, 'vision']);

// Merge only if newAvenger value is not null
oldAvengers.mergeWith((oldAvenger, newAvenger, index) => {
  return (newAvenger === null) ? oldAvenger : newAvenger
}, newAvengers);


Merge lists and resolve conflicts according to index


// Merge every other List item with mergeWith()

const oldAvengers = Immutable.List(
   ['ironMan', 'captainAmerica', 'blackWidow', 'theHulk']
);
const newAvengers = Immutable.List(
   ['scarletWitch', 'vision', 'antMan', 'falcon']
);

// Merge every other item
oldAvengers.mergeWith((oldAvenger, newAvenger, index) => {
    return (index % 2) ? newAvenger : oldAvenger
}, newAvengers);


mergeDeep()

mergeDeep() does what merge does, but for nested Lists, iterating through each level it finds.

Merge two nested Lists together and let Immutable resolve conflicts

merge() overwrites the value of each item in a List with the value in the merging List that exists at the corresponding index. However, in the case of a nested List, this could potentially overwrite an entire nested List, rather than a single item.

Take the following example:


// Merge two nested Lists together with merge()

const oldAvengers = Immutable.fromJS(
    [
        ['ironMan', ['captainAmerica']],
        ['theHulk', ['Thor']]
    ]);

const newAvengers = Immutable.fromJS(
    [
        ['vision'],
        [
            ['blackWidow']
        ]
    ]);

// This overwrites everything in oldAvengers
oldAvengers.merge(newAvengers);

The newAvengers List items overwrite all of the corresponding items in oldAvengers (e.g. ‘vision’ overwrites ‘ironMan’ and the nested List containing ‘captainAmerica’).

To preserve the nesting of a List and target a specific level of nesting, you need to use mergeDeep:


// Merge two nested Lists together with mergeDeep()

const oldAvengers = Immutable.fromJS(
    [
        ['ironMan', ['captainAmerica']],
        ['theHulk', ['Thor']]
    ]);

const newAvengers = Immutable.fromJS(
    [
        ['vision'],
        [
            ['blackWidow']
        ]
    ]);

// This leaves the nested Lists intact
oldAvengers.mergeDeep(newAvengers);


mergeDeepWith()

If you need to make your own decisions on which nested item should be merged, used mergeDeepWtih:

Merge two nested Lists together and resolve conflicts yourself

list1.mergeDeepWith(conflictResolutionFn(list1Value, list2Value, index){}, list2)


// Merge two nested Lists together with mergeDeepWith()

const oldAvengers = Immutable.fromJS(
    [
        ['ironMan', ['captainAmerica']],
        ['theHulk', ['Thor']]
    ]);

const newAvengers = Immutable.fromJS(
    [
        ['vision'],
        ['blackWidow', 'Loki']        
    ]);

// Loki can't replace Thor
oldAvengers.mergeDeepWith((prev, next, index) => {
	return (next === 'Loki') ? prev : next
}, newAvengers);

Merging can be tricky to get your head around at times, particularly with deeply nested Lists. However, the ability to use your own conflict resolution functions provides a powerful mechanism for manipulating data.

There are no comments.

Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>