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 oforiginalList
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-inconflictResolutionFn()
to resolve any conflictsmergeDeep(List1, List2, List3...List-n)
– merges Lists together, and if a conflict exists, it merges the conflicting items anywaymergeDeepWith(conflictResolutionFn, List1, List2, List3...List-n)
– merges Lists together, and if a conflict exists, it uses the passed-inconflictResolutionFn()
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 atoldAvengers[0]
); ‘vision’ overwrites ‘captainAmerica’; butnewAvengers[2]
doesn’t exist, sooldAvengers[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.
All Immutable.js Tutorials in this Series
This is just one tutorial in this in-depth series of Immutable.js tutorials. Here are the others, which all contain a wealth of information and examples (and all in JavaScript!).
Introduction
Lists
- The Foolproof Guide to Creating Lists
- Get, Set and Delete data from an Immutable List
- Merging Lists Finally Explained
Maps
- Every Way to Create an Immutable.js Map
- Get, Set, Delete and Update data from an Immutable Map
- 6 Ways to Merge Maps in Immutable.js