Home > Back-end >  What's the difference between addAll() vs followedBy() in Dart lists?
What's the difference between addAll() vs followedBy() in Dart lists?

Time:08-29

I need to concatenate two lists in Dart and saw that there are at least two different methods to do so. One is list1.addAll(list2) and the other is list1.followedBy(list2). I wonder what's the difference? The documentation refers to the latter as "lazy concatenation". Does it mean that under the hood the elements are copied in the first case, but only referenced in the latter? Or is there something more?

CodePudding user response:

Lazy loading (in this case lazy concatenation) means that some resources are not evaluated before they are necessary. By contrast, eager loading (or eager concatenation) means that the resource is fully evaluated.

So, lazy concatenation means that the concatenation is known to be executed, but its final evaluation is postponed until it is needed. Also, eager concatenation means that the whole concatenation process is fully done.

CodePudding user response:

list1.addAll(list2) grows and mutates list1 to include the elements of list2. If list2 has m elements, then memory consumption from list1.addAll(list2) will by grow O(m).

More visually, if you have:

list1                  list2
 --- --- --- ---        --- --- 
| o | o | o | o |      | o | o |
 -|- -|- -|- -|-        -|- -|- 
  |   |   |   |          |   |
  v   v   v   v          v   v
  A   B   C   D          E   F

then list1.addAll(list2) will produce:

list1                       list2
 --- --- --- --- --- ---     --- --- 
| o | o | o | o | o | o |   | o | o |
 -|- -|- -|- -|- -|- -|-     -|- -|- 
  |   |   |   |   |   |       |   |
  v   v   v   v    \   \______|__ |
  A   B   C   D     \   ______/  \|
                     \ /          |
                      |           v
                      v           F
                      E

Note that mutating list2 afterward will not affect the contents of list1.

list1.followedBy(list2) returns an Iterable (not a List). When you iterate over the that Iterable, you will iterate over list1 and then iterate over list2. list1.followedBy(list2) does not not mutate list1 and should not allocate a new List. Memory consumption from list1.addAll(list2) will grow by O(1) since no Lists are grown nor created.

In this case, mutating list2 afterward will affect* the Iterable returned by followedBy:

void main() {
  var list1 = [1, 2, 3];
  var list2 = [4, 5, 6];
  
  var list1Copy = [...list1];
  list1Copy.addAll(list2);
  
  print(list1Copy); // Prints: [1, 2, 3, 4, 5, 6]
   
  var concatenated = list1.followedBy(list2);
  print(concatenated.toList()); // Prints: [1, 2, 3, 4, 5, 6]

  list2.add(7);
  print(list1Copy); // Prints: [1, 2, 3, 4, 5, 6]
  print(concatenated.toList()); // Prints: [1, 2, 3, 4, 5, 6, 7]
}```
  • Related