Skip to content

Instantly share code, notes, and snippets.

@Maistho
Created April 10, 2022 19:26
Show Gist options
  • Save Maistho/b3e07d2bd4170fdf3b0244afeb3f9f17 to your computer and use it in GitHub Desktop.
Save Maistho/b3e07d2bd4170fdf3b0244afeb3f9f17 to your computer and use it in GitHub Desktop.
Dart mapWithIndex()
typedef _Transformation<S, T> = T Function(S value, int index);
abstract class EfficientLengthIterableWithIndex<T> extends Iterable<T> {
const EfficientLengthIterableWithIndex();
/**
* Returns the number of elements in the iterable.
*
* This is an efficient operation that doesn't require iterating through
* the elements.
*/
@override
int get length;
}
extension IndexMap<E> on Iterable<E> {
Iterable<T> mapWithIndex<T>(T Function(E e, int i) toElement) =>
MappedIterableWithIndex(this, toElement);
}
class MappedIterableWithIndex<S, T> extends Iterable<T> {
final Iterable<S> _iterable;
final _Transformation<S, T> _f;
factory MappedIterableWithIndex(
Iterable<S> iterable, T Function(S value, int i) function) {
if (iterable is EfficientLengthIterableWithIndex) {
return EfficientLengthMappedIterableWithIndex<S, T>(iterable, function);
}
return MappedIterableWithIndex<S, T>._(iterable, function);
}
MappedIterableWithIndex._(this._iterable, this._f);
@override
Iterator<T> get iterator =>
MappedIteratorWithIndex<S, T>(_iterable.iterator, _f);
// Length related functions are independent of the mapping.
@override
int get length => _iterable.length;
@override
bool get isEmpty => _iterable.isEmpty;
// Index based lookup can be done before transforming.
@override
T get first => _f(_iterable.first, 0);
@override
T get last => _f(_iterable.last, _iterable.length - 1);
@override
T get single => _f(_iterable.single, 0);
@override
T elementAt(int index) => _f(_iterable.elementAt(index), index);
}
class EfficientLengthMappedIterableWithIndex<S, T>
extends MappedIterableWithIndex<S, T>
implements EfficientLengthIterableWithIndex<T> {
EfficientLengthMappedIterableWithIndex(
Iterable<S> iterable, T Function(S value, int index) function)
: super._(iterable, function);
}
class MappedIteratorWithIndex<S, T> extends Iterator<T> {
T? _current;
int index = 0;
final Iterator<S> _iterator;
final _Transformation<S, T> _f;
MappedIteratorWithIndex(this._iterator, this._f);
@override
bool moveNext() {
if (_iterator.moveNext()) {
_current = _f(_iterator.current, index++);
return true;
}
_current = null;
return false;
}
@override
T get current => _current as T;
}
void main() {
final List<String> list = ['a','b','c','d','e','f','g','h'];
print(list.mapWithIndex((e,i) => '$i: $e').toList());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment