Related
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]
}
}
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;
}
I have multiple lists of integers.
val firstList: ArrayList<Int> = arrayListOf(1, 1, 1, 2, 3, 4)
val secondList: ArrayList<Int> = arrayListOf(1, 4, 5, 6, 6, 6, 7, 8)
val thirdList: ArrayList<Int> = arrayListOf(1, 6, 9)
...
I need to remove duplicates only among the other lists, and not within a list itself.
The result should be:
[1,1,1,2,3,4,5,6,6,6,7,8,9]
What is the best approach to do so in Kotlin?
We can filter the additional lists with a .filter and .contains, then add the result to the firstList. Not sure if this is the most efficient way, but it should work.
val firstList: ArrayList<Int> = arrayListOf(1, 1, 1, 2, 3, 4)
val secondList: ArrayList<Int> = arrayListOf(1, 4, 5, 6, 6, 6, 7, 8)
val thirdList: ArrayList<Int> = arrayListOf(1, 6, 9)
firstList += secondList.filterNot { firstList.contains(it) }
firstList += thirdList.filterNot { firstList.contains(it) }
firstList.sort() //not sure if you want the firstList to be sorted or not
You could also make it an extension function, so then it is easier to call.
fun <T> MutableCollection<T>.addOtherNoDuplicates(vararg others: Iterable<T>){
others.forEach {other ->
this += other.filterNot { this.contains(it) }
}
}
Then the call would just be:
firstList.addOtherNoDuplicates(secondList, thirdList) //add as many as you want
firstList.sort()
If you only want to use it for ArrayList, then you can replace the MutableCollection<T> with ArrayList<T> and use the sort() directly in the function itself.
If these are very long lists, you can use a MutableSet on the side to efficiently avoid adding the unwanted values.
val input = listOf(firstList, secondList, thirdList)
val allValues = mutableSetOf<Int>()
val result = mutableListOf<Int>()
for (list in input) {
val newValues = list.filterNot { it in allValues }
result.addAll(newValues)
allValues.addAll(newValues)
}
println(result)
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);
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;
}