Alex
Alex

Reputation: 2233

How do I combine two lists in Dart?

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]

Upvotes: 223

Views: 178951

Answers (14)

nafsaka
nafsaka

Reputation: 1032

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];
  • final List<int> c = [a, b].flattened;

Here is the benchmark code:

import 'package:benchmark_harness/benchmark_harness.dart';
import 'package:collection/collection.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);
  }
}

class Benchmark9 extends BenchmarkBase {
  const Benchmark9() : super('c = concatLists([a, b]) ');

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

  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;
  }
}

class Benchmark10 extends BenchmarkBase {
  const Benchmark10() : super('a.forEach((e) => b.add(e)) ');

  @override
  void run() {
    a.forEach((e) => b.add(e));
  }
}

class Benchmark11 extends BenchmarkBase {
  const Benchmark11() : super('[a, b].flattened ');

  @override
  void run() {
    [a, b].flattened;
  }
}

class Benchmark12 extends BenchmarkBase {
  const Benchmark12() : super('c = [ for() a[i], for() b[i] ] ');

  @override
  void run() {
    final List<int> c = [
      for (var i =0; i<a.length;  i++) a[i],
      for (var i =0; i<b.length;  i++) b[i],
    ];
  }
}

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

And the result:

c = a + b (RunTime): 0.5087239553641948 us.
c = a.followedBy(b).toList() (RunTime): 1.0383009808495096 us.
c = [a, b].expand((x) => x).toList() (RunTime): 1.9536091666666666 us.
c = [a, b].reduce((value, element) => value + element) (RunTime): 0.768018 us.
c = [a, b].fold([], (previousValue, element) => previousValue + element) (RunTime): 1.2125958937020531 us.
a.addAll(b) (RunTime): 1.7318055 us.
c = <int>[...a, ...b] (RunTime): 0.49604125553047174 us.
c = List.from(a)..addAll(b) (RunTime): 0.60551975 us.
c = concatLists([a, b]) (RunTime): 0.8764710383981061 us.
a.forEach((e) => b.add(e)) (RunTime): 1.4383115 us.
[a, b].flattened (RunTime): 0.471882834053767 us.
c = [ for() a[i], for() b[i] ] (RunTime): 0.5955005 us.

Dart Version:

Dart SDK version: 3.4.3 (stable) (Tue Jun 4 19:51:39 2024 +0000) on "macos_x64"

Upvotes: 9

Victor Gorban
Victor Gorban

Reputation: 1681

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(...) .

Upvotes: 0

Anandh Krishnan
Anandh Krishnan

Reputation: 5984

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]

Upvotes: 1

Adelina
Adelina

Reputation: 11881

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

var newList = {...list1, ...list2}.toList(); 

Upvotes: 20

iDecode
iDecode

Reputation: 28906

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();

Upvotes: 5

Stuck
Stuck

Reputation: 12292

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.

Upvotes: 4

sid
sid

Reputation: 2027

For Dart 2.3+ & the people from JavaScript community:

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

toSet() will filter and return only unique items.

Upvotes: 4

Yunus Kocatas
Yunus Kocatas

Reputation: 316

 list1.followedBy(list2).toList();

Upvotes: 1

Aleksandar
Aleksandar

Reputation: 4144

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]
}

Upvotes: 3

user8787628
user8787628

Reputation:

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!

Upvotes: 3

Alexandre Ardhuin
Alexandre Ardhuin

Reputation: 76193

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];

Upvotes: 485

Erlend
Erlend

Reputation: 1969

Dart now supports concatenation of lists using the + operator.

Example:

List<int> result = [0, 1, 2] + [3, 4, 5];

Upvotes: 29

Daniel Robinson
Daniel Robinson

Reputation: 14868

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 :)

Upvotes: 10

Ticore Shih
Ticore Shih

Reputation: 375

maybe more consistent~

var list = []..addAll(list1)..addAll(list2);

Upvotes: 21

Related Questions