Reputation: 2233
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
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
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
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
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
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
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
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
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):
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
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
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
Reputation: 1969
Dart now supports concatenation of lists using the +
operator.
Example:
List<int> result = [0, 1, 2] + [3, 4, 5];
Upvotes: 29
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
Reputation: 375
maybe more consistent~
var list = []..addAll(list1)..addAll(list2);
Upvotes: 21