Split list into some part in dart [duplicate] - list
Assume I have a list like:
var letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
I would like a list of lists of 2 elements each:
var chunks = [['a', 'b'], ['c', 'd'], ['e', 'f'], ['g', 'h']];
What's a good way to do this with Dart?
Here is another way:
var chunks = [];
int chunkSize = 2;
for (var i = 0; i < letters.length; i += chunkSize) {
chunks.add(letters.sublist(i, i+chunkSize > letters.length ? letters.length : i + chunkSize));
}
return chunks;
Run it on dartpad
Quiver (version >= 0.18) supplies partition() as part of its iterables library (import 'package:quiver/iterables.dart'). The implementation returns lazily-computed Iterable, making it pretty efficient. Use as:
var letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
var pairs = partition(letters, 2);
The returned pairs will be an Iterable<List> that looks like:
[['a', 'b'], ['c', 'd'], ['e', 'f'], ['g', 'h']]
A slight improvement on Seth's answer to make it work with any list or chunk size:
var len = letters.length;
var size = 2;
var chunks = [];
for(var i = 0; i< len; i+= size)
{
var end = (i+size<len)?i+size:len;
chunks.add(letters.sublist(i,end));
}
pairs(list) => list.isEmpty ? list : ([list.take(2)]..addAll(pairs(list.skip(2))));
The official Dart's collection package has slices extension method, used like this:
final letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
final chunks = letters.slices(2); // [['a', 'b'], ['c', 'd'], ['e', 'f'], ['g', 'h']]
another solution;
List chunk(List list, int chunkSize) {
List chunks = [];
int len = list.length;
for (var i = 0; i < len; i += chunkSize) {
int size = i+chunkSize;
chunks.add(list.sublist(i, size > len ? len : size));
}
return chunks;
}
List nums = [1,2,3,4,5];
print(chunk(nums, 2));
// [[1,2], [3,4], [5]]
I found a simple solution:
var subList = mylist.take(3); // take 3 items first
var subList = mylist.skip(2).take(3); // take [2..5] items
Here is one way:
letters.fold([[]], (list, x) {
return list.last.length == 2 ? (list..add([x])) : (list..last.add(x));
});
another way:
extension IterableExtensions<E> on Iterable<E> {
Iterable<List<E>> chunked(int chunkSize) sync* {
if (length <= 0) {
yield [];
return;
}
int skip = 0;
while (skip < length) {
final chunk = this.skip(skip).take(chunkSize);
yield chunk.toList(growable: false);
skip += chunkSize;
if (chunk.length < chunkSize) return;
}
}
}
tests:
void main() {
test("list chunked", () {
final emptyList = [];
final letters = ['a', 'b', 'c', 'd', 'e', 'f'];
final digits = List.generate(32, (index) => index);
print(emptyList.chunked(2));
print(letters.chunked(2));
print(digits.chunked(2));
print(emptyList.chunked(3));
print(letters.chunked(3));
print(digits.chunked(3));
print(emptyList.chunked(5));
print(letters.chunked(5));
print(digits.chunked(5));
});
}
output:
([])
([a, b], [c, d], [e, f])
([0, 1], [2, 3], [4, 5], [6, 7], [8, 9], [10, 11], ..., [28, 29], [30, 31])
([])
([a, b, c], [d, e, f])
([0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11], ..., [27, 28, 29], [30, 31])
([])
([a, b, c, d, e], [f])
([0, 1, 2, 3, 4], [5, 6, 7, 8, 9], [10, 11, 12, 13, 14], ..., [25, 26, 27, 28, 29], [30, 31])
This way works with odd length lists:
var nums = [1, 2, 3, 4, 5];
var pairs = new List.generate(nums.length~/2, (i) => [nums[2 * i], nums[2 * i + 1]]);
Perhaps you might want to throw an error or provide a filler value if the list length is not even.
I would suggest creating an iterable of the pairs, and using .toList if you really need it as a list. This solution can also be applied to any iterable, not just a list. First, a simple solution that only works on lists (with even length)(Like the solution provided from Robert King):
new Iterable.generate(letters.length ~/ 2,
(i) => [letters[2*i], letters[2*i + 1]])
The more general solution is complex:
class mappedIterable extends Object implements Iterable with IterableMixin {
Function generator;
mappedIterable(Iterable source, Iterator this.generator(Iterator in));
Iterator get iterator => generator(source.iterator);
}
class Pairs implements Iterator {
Iterator _source;
List _current = null;
Pairs(Iterator this._source);
List get current => _current;
bool moveNext() {
bool result = _source.moveNext();
_current = [_source.current, (_source..moveNext()).current];
return result;
}
}
Iterable makePairs(Iterable source) =>
new mappedIterable(source, (sourceIterator) => new Pairs(sourceIterator));
print(makePairs(letters))
It seems like it is actually easier to make a stream of pairs from a stream, than to make an iterable of pairs from an iterable.
Here's the old style solution using indexed for loops and generics:
List<List<T>> _generateChunks<T>(List<T> inList, int chunkSize) {
List<List<T>> outList = [];
List<T> tmpList = [];
int counter = 0;
for (int current = 0; current < inList.length; current++) {
if (counter != chunkSize) {
tmpList.add(inList[current]);
counter++;
}
if (counter == chunkSize || current == inList.length - 1) {
outList.add(tmpList.toList());
tmpList.clear();
counter = 0;
}
}
return outList;
}
Using the example
main() {
var letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
int chunkSize = 2;
List<List<String>> chunks = _generateChunks(letters, chunkSize);
print(chunks);
}
The output is:
[[a, b], [c, d], [e, f], [g, h]]
Sublist
You can also extract part of a list using sublist:
var list = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
final middle = list.length ~/ 2;
final part1 = list.sublist(0, middle);
final part2 = list.sublist(middle);
print(part1); // [a, b, c, d]
print(part2); // [e, f, g, h]
Notes:
sublist takes two parameters, start (inclusive) and end (exclusive).
end is optional. If you don't specify an end, then the default is the end of the list.
sublist returns a new list from the given range.
One more solution because some of these look a bit more complicated than necessary:
extension _IterableExtensions<T> on Iterable<T> {
Iterable<List<T>> chunks(int chunkSize) sync* {
final chunk = <T>[];
for (T item in this) {
chunk.add(item);
if (chunk.length == chunkSize) {
yield chunk;
chunk.clear();
}
}
if (chunk.isNotEmpty) yield chunk;
}
}
Influenced by #Alan's answer above and extending List, the equivalent of F# chunkedBySize and windowed and average could be:
import 'dart:collection';
class functionalList<E> extends ListBase<E> {
final List<E> l = [];
functionalList();
void set length(int newLength) { l.length = newLength; }
int get length => l.length;
E operator [](int index) => l[index];
void operator []=(int index, E value) { l[index] = value; }
chunkBySize(int size) => _chunkBySize(l, size);
windowed(int size) => _windowed(l, size);
get average => l.isEmpty
? 0
: l.fold(0, (t, e) => t + e) / l.length;
_chunkBySize(List list, int size) => list.isEmpty
? list
: ([list.take(size)]..addAll(_chunkBySize(list.skip(size), size)));
_windowed(List list, int size) => list.isEmpty
? list
: ([list.take(size)]..addAll(_windowed(list.skip(1), size)));
}
void main() {
var list = new functionalList();
list.addAll([1,2,3]);
print(list.chunkBySize(2));
}
The implementation can be seen here
Late to the party, but to whomever needing this: an extension-based solution:
extension Windowed<E> on Iterable<E> {
Iterable<List<E>> window(int size) sync* {
if (size <= 0) throw ArgumentError.value(size, 'size', "can't be negative");
final Iterator<E> iterator = this.iterator;
while (iterator.moveNext()) {
final List<E> slice = [iterator.current];
for (int i = 1; i < size; i++) {
if (!iterator.moveNext()) break;
slice.add(iterator.current);
}
yield slice;
}
}
}
Split list on equal chunks of size n (the last chunk is the remainder)
Iterable<List<T>> chunks<T>(List<T> lst, int n) sync* {
final gen = List.generate(lst.length ~/ n + 1, (e) => e * n);
for (int i in gen) {
if (i < lst.length)
yield lst.sublist(i, i + n < lst.length ? i + n : lst.length);
}
}
Usage example:
chunks([2, 3, 4, 5, 6, 7, 5, 20, 33], 4).forEach(print);
chunks(['a', 'b', 'c'], 2).forEach(print);
Now that Dart has for loops inside list literals, another possible approach is:
List<List<T>> chunk<T>(List<T> elements, int chunkSize) => [
for (var i = 0; i < elements.length; i+= chunkSize) [
for (var j = 0; j < chunkSize && i + j < elements.length; j++)
elements[i + j]
]
];
or, slightly shorter, but not as efficient:
List<List<T>> chunk<T>(List<T> elements, int chunkSize) => [
for (var i = 0; i < elements.length; i+= chunkSize) [
...elements.getRange(i, i + j)
]
];
Those can, as usual, also be made as extension methods instead, as:
extension ListChunk<T> on List<T> {
List<List<T>> chunk(int chunkSize) =>
... `this` instead of `elements` ...
}
Alternative to sublist using take and skip. Take N elements each time even if the original list is bigger.
List<String> names = [
"Link",
"Alloy",
"Mario",
"Hollow",
"Leon",
"Claire",
"Steve",
"Terry",
"Iori",
"King K. rool"
];
int length = names.length;
int chunkSize = 3;
int index = 0;
while (index < length) {
var chunk = names.skip(index).take(chunkSize);
print(chunk);
index += chunkSize;
}
Output:
(Link, Alloy, Mario)
(Hollow, Leon, Claire)
(Steve, Terry, Iori)
(King K. rool)
Adding my 2 cents on this question, I wish there was a solution that accepts negative numbers (to allow chunk in reverse order), so here we are:
import 'dart:math';
extension ChunkedList<T> on List<T> {
List<List<T>> chunked(int size, {bool incomplete = false}) {
if (size == 0) {
throw ArgumentError.value(
size,
'chunked',
'[size] must be a non-zero integer.',
);
}
final List<T> target = size.isNegative ? reversed.toList() : toList();
final int n = size.abs();
final int base = incomplete ? (length / n).ceil() : (length / n).floor();
return <List<T>>[
for (int i = 0; i < base; i++)
target.sublist(i * n, min((i + 1) * n, length)),
];
}
}
Usage:
print(<int>[1, 2, 3, 4, 5].chunked(2, incomplete: false)); // [[1, 2], [3, 4]]
print(<int>[1, 2, 3, 4, 5].chunked(2, incomplete: true)); // [[1, 2], [3, 4], [5]]
print(<int>[1, 2, 3, 4, 5].chunked(-2, incomplete: false)); // [[5, 4], [3, 2]]
print(<int>[1, 2, 3, 4, 5].chunked(-2, incomplete: true)); // [[5, 4], [3, 2], [1]]
Fully-typed.
Supports any type.
Support negative numbers.
Try it online.
This function returns the sublist from an original array given the chunk size.
chunkArray(List<dynamic> original, int size) {
var sublist = List.generate((original.length ~/ size) + 1, (e) => []);
for (var i = 0; i < sublist.length; i++) {
int remaining=(original.length - i * size);
sublist[i] = original.sublist(
i * size,
i * size +
( remaining> size
? size
: remaining));
}
return sublist;
}
Related
Generate a random list based on limited items with spock-genesis
I use spock-genesis and would like to have an infinite lists generator parametrized with a list of values. A generated item should be a list that contains at most the list of parametrized values in random order. Some invariants are: def 'list generator'() { expect: xs.size() <= 3 xs.findAll({x -> x == 1}).size() <= 1 xs.findAll({x -> x == 2}).size() <= 1 xs.findAll({x -> x == 3}).size() <= 1 where: xs << listGen([1, 2, 3]) } I'm about to write own Generator implementation but there is chance I overthink something and it's possible to compose such generator with already existing spock-genesis units.
Try this List listGen(List list) { list.subsequences() .collect { it.permutations() } .inject([[]]) { result, subseq -> result + subseq } } The result of listGen([1, 2, 3]) will be: [[], [1], [1, 2, 3], [3, 2, 1], [2, 1, 3], [3, 1, 2], [1, 3, 2], [2, 3, 1], [2], [3, 2], [2, 3], [2, 1], [1, 2], [3], [1, 3], [3, 1]] Your test passes with this implementation. UPD: As per the OP clarifications below in the comments, they expect the permutations to be random, so here is the line of code that will do that using spock-genesis any: where: xs << Gen.any(listGen([1, 2, 3])).take(42).collect() // I assume 42 here should be random as well then
I'm not quite sure what you want, is just a list of every possible permutation of the list [1,2,3]? If so then this should be enough. [1, 2, 3].permutations()
With #Dmitry Khamitov help I've come up with spock-genesis generator package spock.genesis.generators.composites import groovy.transform.CompileStatic import spock.genesis.generators.Generator import spock.genesis.generators.UnmodifiableIterator import spock.genesis.generators.values.RandomElementGenerator /** A lazy infinite {#code Generator} that returns a random subset of elements from a source Collection * #warning O(n!) time complexity. Starts being too expensive with lists 10+ elements * #param < E > the generated type */ #CompileStatic class ListSubsetGenerator<E> extends Generator<List<E>> { final RandomElementGenerator<List<E>> valueSource ListSubsetGenerator(Collection<E> source) { this.valueSource = new RandomElementGenerator<>(getListsSource(source)) } private List<List<E>> getListsSource(Collection<E> source) { source.toList().subsequences() .collect { it.permutations() } .inject([[]]) { result, subseq -> result.addAll(subseq) result } as List<List<E>> } #Override UnmodifiableIterator<List<E>> iterator() { new UnmodifiableIterator<List<E>>() { private final Iterator<List<E>> source = valueSource.iterator() #Override boolean hasNext() { source.hasNext() } #Override List<E> next() { source.next() } } } #Override Generator<List<E>> seed(Long seed) { super.seed(seed) valueSource.seed(seed) this } } Here are some tests: class ListSubsetGeneratorTest extends Specification { #Iterations(100) def 'test invariants'() { expect: xs.size() <= 3 xs.findAll({x -> x == 1}).size() <= 1 xs.findAll({x -> x == 2}).size() <= 1 xs.findAll({x -> x == 3}).size() <= 1 xs.every { [1, 2, 3].contains(it) } where: xs << new ListSubsetGenerator([1, 2, 3]) } def 'setting seed produces the same sequences for different generators'() { given: def elements = ['a', 'b', 'c', 'd'] def xs = new ListSubsetGenerator(elements).seed(seed).take(100).realized def ys = new ListSubsetGenerator(elements).seed(seed).take(100).realized expect: xs == ys where: seed << [Long.MIN_VALUE, 100, Long.MAX_VALUE] } }
appending function returns unexpected results, Dart
this is the pyramid problem which is : Write a function that when given a number >= 0, returns an Array of ascending length subarrays. pyramid(0) => [ ] pyramid(1) => [ [1] ] pyramid(2) => [ [1], [1, 1] ] pyramid(3) => [ [1], [1, 1], [1, 1, 1] ] the solution i wrote is : List<List<int>> pyramid(int n) { List<List<int>> bigList = []; List<int> smallList = []; for (int i = 0; i < n; i++) { //1: i==1, i==2 smallList.add(1); // bigList.add([smallList]); won't work because it takes only integers in parameters List<List<int>> fixedList = [smallList]; print(fixedList); bigList.addAll([smallList]); print(bigList); // bigList,[[1]] } print(bigList); return bigList; } void main() { pyramid(3); } the output I get is not the one wanted, here is the output with the prints to know what happens in each iteration: [[1]] [[1]] [[1, 1]] [[1, 1], [1, 1]] [[1, 1, 1]] [[1, 1, 1], [1, 1, 1], [1, 1, 1]] [[1, 1, 1], [1, 1, 1], [1, 1, 1]] My question is: (and I am looking to find my mistake not the right answer)I dont understand why at the end of first iteration i=0, bigList has [1] as a first element. but has [1,1] as a first element in the end of the second iteration. why did the first element of bigList change. all I am doing is appending to the list. right?
List<List<Object>> makePyramid(int n) { if (n < 1) return []; var result = List.generate(n, (i) => List.filled(i+1, 1)); return result; } void main(List<String> args) { List.generate(4, (i) => i).forEach((e) => print(makePyramid(e))); } Output: [] [[1]] [[1], [1, 1]] [[1], [1, 1], [1, 1, 1]]
Dart: Check items in List of lists
Before adding a list I want to check that it does not exist so there are no repeated values. This works with a list of integers, but not with a list of other integer lists: void main() { var listasN = List<int>(); var n1 = 1; var n2 = 2; var n3 = 1; void addN(int n) { if (!listasN.contains(n)) { listasN.add(n); } } addN(n1); addN(n2); addN(n3); print(listasN); var listas = List<List<int>>(); var lista1 = [1, 2, 3, 4]; var lista2 = [5, 6, 7, 8]; var lista3 = [1, 2, 3, 4]; void addLista(List<int> ls) { if (!listas.contains(ls)) { listas.add(ls); } } addLista(lista1); addLista(lista2); addLista(lista3); print(listas); } Out: [1, 2] [[1, 2, 3, 4], [5, 6, 7, 8], [1, 2, 3, 4]] The first function does not support repeated values, but the second does, why?
Dart lists do not have an inherent equality. That is, the == operator only considers lists equal if it's the same list, not if it's different lists with the same content. That's generally how Dart handles equality of mutable types. The contains method uses equality for checking. So, what you can do instead is to create a "list equals" method: bool listEquals<T>(List<T> list1, List<T> list2) { if (list1.length != list2.length) return false; for (var i = 0; i < list1.length; i++) { if (list1[i] != list2[i]) return false; } return true; } Then you can check if a similar list is contained in your lists: void addLista(List<int> ls) { if (!listas.any((ls2) => listEquals(ls, ls2))) { listas.add(ls); } }
Is there a Dart utility for converting a flat list into a nested one?
It's a common problem here, but I couldn't find any simplified methods for Dart in particular - how can I convert a list like this [1, 2, 3, 4, 5, 6] into a list like this [[1, 2], [3,4], [5,6]] assuming there are no extra elements after this?
Dart Quiver package is a set of utility libraries for Dart that makes using many Dart libraries easier and more convenient or adds additional functionality (https://github.com/google/quiver-dart). You can use the partition function from quiver iterables library as follows. import 'package:quiver/iterables.dart'; main() { var list = [1, 2, 3, 4, 5, 6]; # Use partition function to segment lists into chunks of size 2 var newList = partition<int>(list, 2); print (newList); } Result [[1, 2], [3,4], [5,6]]
var list = [1, 2, 3, 4]; List<int> temp = []; List<List<int>> newList = list.fold<List<List<int>>>([], (newList, i) { if (temp.length < 2) { temp.add(i); } if (temp.length >= 2) { List<int> newValue = new List<int>.from(temp); newList.add(newValue); temp.clear(); } return newList; }); print(newList);
How do I split or chunk a list into equal parts, with Dart?
Assume I have a list like: var letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']; I would like a list of lists of 2 elements each: var chunks = [['a', 'b'], ['c', 'd'], ['e', 'f'], ['g', 'h']]; What's a good way to do this with Dart?
Here is another way: var chunks = []; int chunkSize = 2; for (var i = 0; i < letters.length; i += chunkSize) { chunks.add(letters.sublist(i, i+chunkSize > letters.length ? letters.length : i + chunkSize)); } return chunks; Run it on dartpad
Quiver (version >= 0.18) supplies partition() as part of its iterables library (import 'package:quiver/iterables.dart'). The implementation returns lazily-computed Iterable, making it pretty efficient. Use as: var letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']; var pairs = partition(letters, 2); The returned pairs will be an Iterable<List> that looks like: [['a', 'b'], ['c', 'd'], ['e', 'f'], ['g', 'h']]
A slight improvement on Seth's answer to make it work with any list or chunk size: var len = letters.length; var size = 2; var chunks = []; for(var i = 0; i< len; i+= size) { var end = (i+size<len)?i+size:len; chunks.add(letters.sublist(i,end)); }
pairs(list) => list.isEmpty ? list : ([list.take(2)]..addAll(pairs(list.skip(2))));
The official Dart's collection package has slices extension method, used like this: final letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']; final chunks = letters.slices(2); // [['a', 'b'], ['c', 'd'], ['e', 'f'], ['g', 'h']]
another solution; List chunk(List list, int chunkSize) { List chunks = []; int len = list.length; for (var i = 0; i < len; i += chunkSize) { int size = i+chunkSize; chunks.add(list.sublist(i, size > len ? len : size)); } return chunks; } List nums = [1,2,3,4,5]; print(chunk(nums, 2)); // [[1,2], [3,4], [5]]
I found a simple solution: var subList = mylist.take(3); // take 3 items first var subList = mylist.skip(2).take(3); // take [2..5] items
Here is one way: letters.fold([[]], (list, x) { return list.last.length == 2 ? (list..add([x])) : (list..last.add(x)); });
another way: extension IterableExtensions<E> on Iterable<E> { Iterable<List<E>> chunked(int chunkSize) sync* { if (length <= 0) { yield []; return; } int skip = 0; while (skip < length) { final chunk = this.skip(skip).take(chunkSize); yield chunk.toList(growable: false); skip += chunkSize; if (chunk.length < chunkSize) return; } } } tests: void main() { test("list chunked", () { final emptyList = []; final letters = ['a', 'b', 'c', 'd', 'e', 'f']; final digits = List.generate(32, (index) => index); print(emptyList.chunked(2)); print(letters.chunked(2)); print(digits.chunked(2)); print(emptyList.chunked(3)); print(letters.chunked(3)); print(digits.chunked(3)); print(emptyList.chunked(5)); print(letters.chunked(5)); print(digits.chunked(5)); }); } output: ([]) ([a, b], [c, d], [e, f]) ([0, 1], [2, 3], [4, 5], [6, 7], [8, 9], [10, 11], ..., [28, 29], [30, 31]) ([]) ([a, b, c], [d, e, f]) ([0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11], ..., [27, 28, 29], [30, 31]) ([]) ([a, b, c, d, e], [f]) ([0, 1, 2, 3, 4], [5, 6, 7, 8, 9], [10, 11, 12, 13, 14], ..., [25, 26, 27, 28, 29], [30, 31])
This way works with odd length lists: var nums = [1, 2, 3, 4, 5]; var pairs = new List.generate(nums.length~/2, (i) => [nums[2 * i], nums[2 * i + 1]]); Perhaps you might want to throw an error or provide a filler value if the list length is not even.
I would suggest creating an iterable of the pairs, and using .toList if you really need it as a list. This solution can also be applied to any iterable, not just a list. First, a simple solution that only works on lists (with even length)(Like the solution provided from Robert King): new Iterable.generate(letters.length ~/ 2, (i) => [letters[2*i], letters[2*i + 1]]) The more general solution is complex: class mappedIterable extends Object implements Iterable with IterableMixin { Function generator; mappedIterable(Iterable source, Iterator this.generator(Iterator in)); Iterator get iterator => generator(source.iterator); } class Pairs implements Iterator { Iterator _source; List _current = null; Pairs(Iterator this._source); List get current => _current; bool moveNext() { bool result = _source.moveNext(); _current = [_source.current, (_source..moveNext()).current]; return result; } } Iterable makePairs(Iterable source) => new mappedIterable(source, (sourceIterator) => new Pairs(sourceIterator)); print(makePairs(letters)) It seems like it is actually easier to make a stream of pairs from a stream, than to make an iterable of pairs from an iterable.
Here's the old style solution using indexed for loops and generics: List<List<T>> _generateChunks<T>(List<T> inList, int chunkSize) { List<List<T>> outList = []; List<T> tmpList = []; int counter = 0; for (int current = 0; current < inList.length; current++) { if (counter != chunkSize) { tmpList.add(inList[current]); counter++; } if (counter == chunkSize || current == inList.length - 1) { outList.add(tmpList.toList()); tmpList.clear(); counter = 0; } } return outList; } Using the example main() { var letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']; int chunkSize = 2; List<List<String>> chunks = _generateChunks(letters, chunkSize); print(chunks); } The output is: [[a, b], [c, d], [e, f], [g, h]]
Sublist You can also extract part of a list using sublist: var list = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']; final middle = list.length ~/ 2; final part1 = list.sublist(0, middle); final part2 = list.sublist(middle); print(part1); // [a, b, c, d] print(part2); // [e, f, g, h] Notes: sublist takes two parameters, start (inclusive) and end (exclusive). end is optional. If you don't specify an end, then the default is the end of the list. sublist returns a new list from the given range.
One more solution because some of these look a bit more complicated than necessary: extension _IterableExtensions<T> on Iterable<T> { Iterable<List<T>> chunks(int chunkSize) sync* { final chunk = <T>[]; for (T item in this) { chunk.add(item); if (chunk.length == chunkSize) { yield chunk; chunk.clear(); } } if (chunk.isNotEmpty) yield chunk; } }
Influenced by #Alan's answer above and extending List, the equivalent of F# chunkedBySize and windowed and average could be: import 'dart:collection'; class functionalList<E> extends ListBase<E> { final List<E> l = []; functionalList(); void set length(int newLength) { l.length = newLength; } int get length => l.length; E operator [](int index) => l[index]; void operator []=(int index, E value) { l[index] = value; } chunkBySize(int size) => _chunkBySize(l, size); windowed(int size) => _windowed(l, size); get average => l.isEmpty ? 0 : l.fold(0, (t, e) => t + e) / l.length; _chunkBySize(List list, int size) => list.isEmpty ? list : ([list.take(size)]..addAll(_chunkBySize(list.skip(size), size))); _windowed(List list, int size) => list.isEmpty ? list : ([list.take(size)]..addAll(_windowed(list.skip(1), size))); } void main() { var list = new functionalList(); list.addAll([1,2,3]); print(list.chunkBySize(2)); } The implementation can be seen here
Late to the party, but to whomever needing this: an extension-based solution: extension Windowed<E> on Iterable<E> { Iterable<List<E>> window(int size) sync* { if (size <= 0) throw ArgumentError.value(size, 'size', "can't be negative"); final Iterator<E> iterator = this.iterator; while (iterator.moveNext()) { final List<E> slice = [iterator.current]; for (int i = 1; i < size; i++) { if (!iterator.moveNext()) break; slice.add(iterator.current); } yield slice; } } }
Split list on equal chunks of size n (the last chunk is the remainder) Iterable<List<T>> chunks<T>(List<T> lst, int n) sync* { final gen = List.generate(lst.length ~/ n + 1, (e) => e * n); for (int i in gen) { if (i < lst.length) yield lst.sublist(i, i + n < lst.length ? i + n : lst.length); } } Usage example: chunks([2, 3, 4, 5, 6, 7, 5, 20, 33], 4).forEach(print); chunks(['a', 'b', 'c'], 2).forEach(print);
Now that Dart has for loops inside list literals, another possible approach is: List<List<T>> chunk<T>(List<T> elements, int chunkSize) => [ for (var i = 0; i < elements.length; i+= chunkSize) [ for (var j = 0; j < chunkSize && i + j < elements.length; j++) elements[i + j] ] ]; or, slightly shorter, but not as efficient: List<List<T>> chunk<T>(List<T> elements, int chunkSize) => [ for (var i = 0; i < elements.length; i+= chunkSize) [ ...elements.getRange(i, i + j) ] ]; Those can, as usual, also be made as extension methods instead, as: extension ListChunk<T> on List<T> { List<List<T>> chunk(int chunkSize) => ... `this` instead of `elements` ... }
Alternative to sublist using take and skip. Take N elements each time even if the original list is bigger. List<String> names = [ "Link", "Alloy", "Mario", "Hollow", "Leon", "Claire", "Steve", "Terry", "Iori", "King K. rool" ]; int length = names.length; int chunkSize = 3; int index = 0; while (index < length) { var chunk = names.skip(index).take(chunkSize); print(chunk); index += chunkSize; } Output: (Link, Alloy, Mario) (Hollow, Leon, Claire) (Steve, Terry, Iori) (King K. rool)
Adding my 2 cents on this question, I wish there was a solution that accepts negative numbers (to allow chunk in reverse order), so here we are: import 'dart:math'; extension ChunkedList<T> on List<T> { List<List<T>> chunked(int size, {bool incomplete = false}) { if (size == 0) { throw ArgumentError.value( size, 'chunked', '[size] must be a non-zero integer.', ); } final List<T> target = size.isNegative ? reversed.toList() : toList(); final int n = size.abs(); final int base = incomplete ? (length / n).ceil() : (length / n).floor(); return <List<T>>[ for (int i = 0; i < base; i++) target.sublist(i * n, min((i + 1) * n, length)), ]; } } Usage: print(<int>[1, 2, 3, 4, 5].chunked(2, incomplete: false)); // [[1, 2], [3, 4]] print(<int>[1, 2, 3, 4, 5].chunked(2, incomplete: true)); // [[1, 2], [3, 4], [5]] print(<int>[1, 2, 3, 4, 5].chunked(-2, incomplete: false)); // [[5, 4], [3, 2]] print(<int>[1, 2, 3, 4, 5].chunked(-2, incomplete: true)); // [[5, 4], [3, 2], [1]] Fully-typed. Supports any type. Support negative numbers. Try it online.
This function returns the sublist from an original array given the chunk size. chunkArray(List<dynamic> original, int size) { var sublist = List.generate((original.length ~/ size) + 1, (e) => []); for (var i = 0; i < sublist.length; i++) { int remaining=(original.length - i * size); sublist[i] = original.sublist( i * size, i * size + ( remaining> size ? size : remaining)); } return sublist; }