How do I combine two lists in Dart?
Asked Answered
I

14

216

I was wondering if there was an easy way to concatenate two lists in dart to create a brand new list object. I couldn't find anything and something like this:

My list:

list1 = [1, 2, 3]
list2 = [4, 5, 6]

I tried:

var newList = list1 + list2;

I wanted the combined output of:

[1, 2, 3, 4, 5, 6]
Incinerator answered 17/2, 2014 at 10:21 Comment(0)
A
474

You can use:

var newList = new List.from(list1)..addAll(list2);

If you have several lists you can use:

var newList = [list1, list2, list3].expand((x) => x).toList()

As of Dart 2 you can now use +:

var newList = list1 + list2 + list3;

As of Dart 2.3 you can use the spread operator:

var newList = [...list1, ...list2, ...list3];
Attraction answered 17/2, 2014 at 10:24 Comment(4)
An alternative (which allows to easily concatenate many lists): [list1, list2, list3, ...].expand((x) => x).toList();Imaginative
Note that the + operator cannot be be used on lists of different types. (in this case you get an error like type 'List<Widget>' is not a subtype of type 'List<Image>'. ). The spread operator works great for this use case though.Jubilee
Can you please check this question and suggest me something. #62229299Lagoon
And what about performance? No answer is talking about that...Allies
C
25

Dart now supports concatenation of lists using the + operator.

Example:

List<int> result = [0, 1, 2] + [3, 4, 5];
Circumpolar answered 25/11, 2019 at 2:44 Comment(1)
This is the most up-to-date answerDonelson
B
21

maybe more consistent~

var list = []..addAll(list1)..addAll(list2);
Backfire answered 19/2, 2014 at 16:42 Comment(2)
Old i know but what is the ..addAll() why not just a single dot?Prevail
@Prevail .. is for chaining, to do with out the double dot you would have to: list = []; list.addAll(list1); list.addAll(list2); The way I see it, it basically means call this function, but ignore what it returns, and keep operating on the object we were operating on.Etruria
I
20

If you want to merge two lists and remove duplicates, you convert your final list to a Set using {} :

var newList = {...list1, ...list2}.toList(); 
Instruction answered 16/1, 2020 at 11:52 Comment(1)
var newList = {...list1, ...list2}.toList();Disquietude
R
10

Alexandres' answer is the best but if you wanted to use + like in your example you can use Darts operator overloading:

class MyList<T>{
  List<T> _internal = new List<T>();
  operator +(other) => new List<T>.from(_internal)..addAll(other);
  noSuchMethod(inv){
    //pass all calls to _internal
  }
}

Then:

var newMyList = myList1 + myList2;

Is valid :)

Reidreidar answered 17/2, 2014 at 13:53 Comment(0)
H
7

I collect all possible method and benchmark it using benchmark_harness package.

According to the result the recommended method is:

  • final List<int> c = a + b;
  • final List<int> c = [...a, ...b];

Here is the benchmark code:

import 'package:benchmark_harness/benchmark_harness.dart';

List<int> a = [1, 2, 3];
List<int> b = [4, 5, 6];

class Benchmark1 extends BenchmarkBase {
  const Benchmark1() : super('c = a + b ');

  @override
  void run() {
    final List<int> c = a + b;
  }
}

class Benchmark2 extends BenchmarkBase {
  const Benchmark2() : super('c = a.followedBy(b).toList() ');

  @override
  void run() {
    final List<int> c = a.followedBy(b).toList();
  }
}

class Benchmark3 extends BenchmarkBase {
  const Benchmark3() : super('c = [a, b].expand((x) => x).toList() ');

  @override
  void run() {
    final List<int> c = [a, b].expand((x) => x).toList();
  }
}

class Benchmark4 extends BenchmarkBase {
  const Benchmark4() : super('c = [a, b].reduce((value, element) => value + element) ');

  @override
  void run() {
    final List<int> c = [a, b].reduce((value, element) => value + element);
  }
}

class Benchmark5 extends BenchmarkBase {
  const Benchmark5() : super('c = [a, b].fold([], (previousValue, element) => previousValue + element) ');

  @override
  void run() {
    final List<int> c = [a, b].fold([], (previousValue, element) => previousValue + element);
  }
}

class Benchmark6 extends BenchmarkBase {
  const Benchmark6() : super('a.addAll(b) ');

  @override
  void run() {
    a.addAll(b);
  }
}

class Benchmark7 extends BenchmarkBase {
  const Benchmark7() : super('c = <int>[...a, ...b] ');

  @override
  void run() {
    final List<int> c = <int>[...a, ...b];
  }
}

class Benchmark8 extends BenchmarkBase {
  const Benchmark8() : super('c = List.from(a)..addAll(b) ');

  @override
  void run() {
    final List<int> c = List.from(a)..addAll(b);
  }
}

void main() {
  // Benchmark1().report();
  // Benchmark2().report();
  // Benchmark3().report();
  // Benchmark4().report();
  // Benchmark5().report();
  // Benchmark6().report();
  // Benchmark7().report();
  Benchmark8().report();
}

And the result:

c = a + b (RunTime): 0.8384643860155879 us.
c = a.followedBy(b).toList() (RunTime): 1.3018350015264015 us.
c = [a, b].expand((x) => x).toList() (RunTime): 2.194391139053011 us.
c = [a, b].reduce((value, element) => value + element) (RunTime): 1.1215188056273329 us.
c = [a, b].fold([], (previousValue, element) => previousValue + element) (RunTime): 1.7163271628511283 us.
a.addAll(b) (RunTime): 1.08603684815237 us.
c = <int>[...a, ...b] (RunTime): 0.8498483658053312 us.
c = List.from(a)..addAll(b) (RunTime): 0.9107294347150762 us.

House answered 16/2, 2022 at 12:36 Comment(0)
H
5

If one of your list is nullable, use ...? operator:

var newList = [
  ...?list1,
  ...?list2,
  ...?list3,
];

If you also want to remove duplicate items in the list:

var newList = {
  ...?list1,
  ...?list2,
  ...?list3,
}.toList();
Hamate answered 30/11, 2022 at 10:10 Comment(0)
M
4

Here is another one:

import 'package:collection/collection.dart';

final x = [1, 2, 3];
final y = [4, 5, 6];
final z = [x, y].flattened // Iterable<int>
final result = z.toList();

Note that flattened is defined as extension on Iterable<Iterable<T>> and hence also works with other iterables.

Mingo answered 29/7, 2022 at 8:15 Comment(1)
this one comes from collection package which is now a part of Flutter SDK so do not forget to import 'package:collection/collection.dart';Dillydally
I
3

No need to create a third list in my opinion...

Use this:

list1 = [1, 2, 3];
list2 = [4, 5, 6];
list1.addAll(list2);

print(list1); 
// [1, 2, 3, 4, 5, 6] // is our final result!
Incommunicable answered 15/11, 2020 at 4:58 Comment(0)
B
3

addAll is the most common way to merge two lists.

But to concatenate list of lists, you can use any of these three functions (examples below):

  • expand - Expands each element of an Iterable into zero or more elements,
  • fold - Reduces a collection to a single value by iteratively combining each element of the collection with an existing value,
  • reduce - Reduces a collection to a single value by iteratively combining elements of the collection using the provided function.
void main() {
  List<int> a = [1,2,3];
  List<int> b = [4,5];
  List<int> c = [6];
  List<List<int>> abc = [a,b,c]; // list of lists: [ [1,2,3], [4,5], [6] ]
  List<int> ints = abc.expand((x) => x).toList();
  List<int> ints2 = abc.reduce((list1,list2) => list1 + list2);
  List<int> ints3 = abc.fold([], (prev, curr) => prev + curr); // initial value is []
  print(ints);  // [1,2,3,4,5,6]
  print(ints2); // [1,2,3,4,5,6]
  print(ints3); // [1,2,3,4,5,6]
}
Bounder answered 20/1, 2021 at 14:49 Comment(0)
S
3

For Dart 2.3+ & the people from JavaScript community:

var mergedList = [...listX, ...listY, ...listZ].toSet(); 

toSet() will filter and return only unique items.

Saber answered 27/1, 2022 at 13:32 Comment(0)
K
1
 list1.followedBy(list2).toList();
Kingcraft answered 27/1, 2022 at 13:21 Comment(1)
It helps more if you supply an explanation why this is the preferred solution and explain how it works. We want to educate, not just provide code.Auricle
S
1

Method 1 -> By using the addAll() function

var array1 = [1, 2, 3];
var array2 = [4, 5, 6];
array1.addAll(array2); // array1 is now [1, 2, 3, 4, 5, 6]

Method 2 -> By using the loop.

var array1 = [1, 2, 3];
var array2 = [4, 5, 6];
array2.forEach((item) {
   array1.add(item);
}); // array1 is now [1, 2, 3, 4, 5, 6]

Method 3 -> By using the + operator.

var array1 = [1, 2, 3];
var array1 = [4, 5, 6];
var newArray = array1 + array1;  // array1 is now [1, 2, 3, 4, 5, 6]
Santinasantini answered 15/5, 2023 at 13:0 Comment(0)
E
0

One note about performance. Keep in mind that all utilizing all those "reduce" methods will create another list for each operation.

So the most performant way (especially for bigger list of lists) will always be "old good C-style":

List<T> concatLists<T>(List<List<T>> listOfLists, [bool isGrowable = true]) {
  if (listOfLists.first.isEmpty) {
    throw Exception('first list of lists cannot be empty');
  }

  int totalLength = 0;
  for (final list in listOfLists) {
    totalLength += list.length;
  }

  List<T> result =
      List<T>.filled(totalLength, listOfLists[0][0], growable: isGrowable);
  int idx = 0;
  for (final list in listOfLists) {
    for (final item in list) {
      result[idx] = item;
      idx += 1;
    }
      // result.addAll(list); // at least 2x longer
  }

  return result;
}

Sure I like to write that syntax sugar too, like [...list1, ...list2], but for larger portions of data you need something more optimized. For example, for converting 50mb data-bytes which is stored in a List<List<int>> into one List<int>.

This approach is at least 2x faster when compared to other approaches. I tested list1 + list2 and listOfLists.reduce(...) .

Ehling answered 29/11, 2023 at 19:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.