A port of .NET's LINQ IEnumerable functions to Dart. This library extends the native Iterable type with all of the LINQ methods that do not exist in native Dart.

API Reference #

Because this library uses Dart 2.6's new extension methods, any Iterable has access to these methods as though they were native methods. This includes classes that extend from Iterable , such as List and Set .

In addition, this library adds several new types of Iterable classes to make some utility functions easier:

// Creates an iterable containing the numbers from 2 to 6: [2, 3, 4, 5, 6] var rangeI = RangeIterable(2, 6, inclusive: true); // Creates an iterable that contains 3 copies of the value 'abc': ['abc', 'abc', 'abc'] var repeatI = RepeatIterable('abc', 3); // Creates an iterable from a string, iterating over its characters // This is an extension getter property on String that returns an // iterable via `String.codeUnits.map((u) => String.fromCodeUnit(u))`. // Results in ['a', 'b', 'c', 'd', 'e', 'f'] var stringI = 'abcdef'.iterable; // Same as above but using `runes` instead of `codeUnits` to respect // rune boundaries and maintain surrogate pairs. var stringIR = 'abcdef'.iterableRunes;

You can call any of 40 new methods on it to modify or analyze it. For example, the native method map is expanded upon with select , which combines the element with the index at which the element is found within the iterable:

var list = [10, 20, 30]; var mappedList = list.select((i, index) => '$index-$i'); // ['1-10', '2-20', '3-30']

There are "OrDefault" variants on several common iterator value getter methods, such as firstOrDefault , singleOrDefault , and defaultIfEmpty . Instead of throwing an error, these methods will return a default value (or null if left unspecified) if the element(s) cannot be found:

var list = <String>[]; var native = list.first; // Throws a StateError var orDefault = list.firstOrDefault('abc'); // Returns 'abc' var list2 = [1, 2, 3]; var importantValue = list2.where((i) => i >= 4) .defaultIfEmpty(-1); // Returns [-1]

You can filter an iterable down to unique instances of elements with the distinct method:

var list = [1, 1, 1, 2, 2, 3, 4, 5, 5, 5, 5, 5]; var uniqueList = myEnum.distinct(); // [1, 2, 3, 4, 5]

There are also set operations with the except , intersect , and union methods:

var listA = [1, 2, 3, 4]; var listB = [3, 4, 5, 6]; var exclusion = listA.except(listB); // [1, 2] var intersection = listA.intersect(listB); // [3, 4] var union = listA.union(listB); // [1, 2, 3, 4, 5, 6]

And you can group elements together by common features using groupBy :

var list = [1, 2, 3, 4, 5, 6]; var groupedList = list.groupBy((i) => i / 3 == 0); // [[1, 2, 4, 5], [3, 6]]

Or bundle them into groups of a fixed length using segment :

var list = [1, 2, 3, 4, 5, 6]; var segmented = list.segment(2); // [[1, 2], [3, 4], [5, 6]]

You can even perform complex ordering functions using orderBy and thenBy :

var list = ['ab', 'a', 'c', 'aa', '']; // Sort by string length followed by alphabetical order var ordered = list.orderBy((c) => c.length) .thenBy((c) => c); // Result: ['', 'a', 'c', 'aa', 'ab']

Just like in native dart, every method returns a new Iterable , so you can chain methods together to make complex mapping, grouping, and filtering behavior:

var list = [3, 1, 6, 2, 3, 2, 4, 1]; var result = list.select((i, idx) => i * 2 + idx) // [6, 3, 14, 8, 10, 10, 14, 9] .distinct() // [6, 3, 14, 8, 10, 9] .where((i) => i > 4) // [6, 14, 8, 10, 9] .orderBy((i) => i) // [6, 8, 9, 10, 14] .map((i) => i.toRadixString(16)); // [6, 8, 9, A, E]

Full Function List #