I want to ask about iterator with a list, I can loop with a list in a while loop.
void main() {
final myList = ['Red', 'Black', 'Green'];
final myIterator = myList.iterator;
while (myIterator.moveNext()) {
print(myIterator.current);
}
}
It is ok and works fine for me, but I want to know how I use for loop or for in loop with iterator?
You rarely need to use an Iterator directly. It is a low level concept.
Use a for-in loop, like so:
for (final element in myList) {
print(element);
}
Related
I have a simple widget subscribed to a Stream of elements.
Each time a new element is received I would like to get also the previous element and decide which one of them pass downstream.
Currently I am using the map operator to store the previous element and calculate the next, like this:
elements.map((e) {
if (this.previous == null) {
this.previous = e;
return e;
}
final next = merge(this.previous, e);
this.previous = e;
return next;
}).listen(...);
How can I do this better and avoid having this.previous?
If you use the rxdart package there is an extension method called pairwise which according to the documentation:
Emits the n-th and n-1th events as a pair. The first event won't be emitted until the second one arrives.
Then you should be able to do something along the lines of this:
elements.pairwise().map((pair) => merge(pair.first, pair.last)).listen(...);
Here is one possibility
void main() {
List list = [12, 24, 48, 60];
list.reduce((value, element) {
print(value + element); // Push to another list maybe?
return element;
});
}
If you are working with a stream try this
void main() {
var counterStream = Stream<int>.periodic(const Duration(seconds: 1), (x) => x)
.reduce((previous, element) {
print(previous + element); // Push to another stream maybe?
return element;
});
}
I want to create a List Stream based on another elements Stream. The List Stream should yield a new list every time an element from the list emits a new value.
Something like this:
Stream<List<Model>> getListStream(List<int> ids) async* {
final List<Model> models = [];
for (var id in ids) {
getModelStream(id).listen((event) {
models.add(event);
});
}
yield models;
}
but it always yields an empty array.
I think the problem is probably the fact the it does not react to the event listener.
How do you deal with this kind of problem?
You're yielding an empty list which will later be filled in.
If you want to wait for the list to be filled in before yielding it, you'll have to do that.
Either:
Stream<List<Model>> getListStream(List<int> ids) async* {
for (var id in ids) {
yield await getModelStream(id).toList();
}
}
or, if you want to start all the streams immediately, and compute them in parallel, and then emit the values when they are done (not necessarily in the original ID order), then:
Stream<List<Model>> getListStream(List<int> ids) {
var controller = StreamController<List<Model>>(sync: true);
controller.onListen = () {
var count = 0;
for (var id in ids) {
count++;
getModelStream(id).toList().then((models) {
controller.add(models);
if (--count == 0) controller.close();
});
}
};
return controller.stream;
}
My goal is to asynchronously return a lazy Iterable created by a generator function. I don't want to return a Stream or use the asnyc* generator since the generation can be done synchronously, only some previous code needs to run asynchronously.
Currently I'm doing it like this, but I wonder if there is any better way to do this?
If this is the only option I probably should outsource the generator function.
Future<Iterable<String>> someAsyncFunction() async {
// some async task
await Future.delayed(Duration(seconds: 1));
Iterable<String> x () sync* {
for (var s in ['1', 'b', 'c']) {
yield s;
}
}
return x();
}
print(await someAsyncFunction());
I was using a self invoked function before, but I wasn't able to specify a return type on it so I changed it to the code above.
Future<Iterable<String>> someAsyncFunction() async {
// some async task
await Future.delayed(Duration(seconds: 1));
return () sync* {
for (var s in ['1', 'b', 'c']) {
yield s;
}
}();
}
Your approach looks perfectly fine.
What I'd probably do myself is to have the function creating the literal as a helper function outside the async function:
Future<Iterable<String>> someAsyncFunction() async {
// some async task
await Future.delayed(Duration(seconds: 1));
return _iterateTheValues(the, values);
}
Iterable<String> _iterateTheValues(Some the, Other values) sync* {
for (var s in combine(the, values)) { // or use yield*.
yield s;
}
}
If you can create a useful iterable from some values after doing an asynchronous operation to find those values, it seems plausible that you'll eventually want to do the same thing with existing values. Maybe just for testing, maybe using a cache. It just feels like the synchronous iteration could be a thing of its own, separate from the asynchronous initialization needed for it.
I want to do something after a lot of future functions are done, but I do not know how to write the code in dart?
the code is like this:
for (var d in data) {
d.loadData().then()
}
// when all loaded
// do something here
but I don't want to wait for them one by one:
for (var d in data) {
await d.loadData(); // NOT NEED THIS
}
how to write those code in dart?
You can use Future.wait to wait for a list of futures:
import 'dart:async';
Future main() async {
var data = [];
var futures = <Future>[];
for (var d in data) {
futures.add(d.loadData());
}
await Future.wait(futures);
}
DartPad example
Existing answer gives enough information, but I want to add a note/warning.
As stated in the docs:
The value of the returned future will be a list of all the values that were produced in the order that the futures are provided by iterating futures.
So, that means that the example below will return 4 as the first element (index 0), and 2 as the second element (index 1).
import 'dart:async';
Future main() async {
print('start');
List<int> li = await Future.wait<int>([
fetchLong(), // longer (which gives 4) is first
fetchShort(), // shorter (which gives 2) is second
]);
print('results: ${li[0]} ${li[1]}'); // results: 4 2
}
Future<int> fetchShort() {
return Future.delayed(Duration(seconds: 3), () {
print('Short!');
return 2;
});
}
Future<int> fetchLong() {
return Future.delayed(Duration(seconds: 5), () {
print('Long!');
return 4;
});
}
If you want to wait for multiple futures of different types and also support null-safety then you can add a helper function similar to the following.
import 'package:tuple/tuple.dart';
Future<Tuple2<T1, T2>> waitConcurrently<T1, T2>(
Future<T1> future1, Future<T2> future2) async {
late T1 result1;
late T2 result2;
await Future.wait([
future1.then((value) => result1 = value),
future2.then((value) => result2 = value)
]);
return Future.value(Tuple2(result1, result2));
}
In order for this to work you need tuples.
At the moment Dart does not provide tuples natively, but there is a package from Google which does: https://pub.dev/packages/tuple
In addition, I'd like to supplement Günter Zöchbauer's answer with FutureOr variant. You'll need to convert your FutureOr<T> variable to Future<T> first and then call wait:
Future.wait(list.map((x) async => x))
I am looking for a way to create a function with a variable number of arguments or parameters in Dart. I know I could create an array parameter instead, but I would prefer to not do that because I'm working on a library where syntactic brevity is important.
For example, in plain JavaScript, we could do something like this (borrowed from here):
function superHeroes() {
for (var i = 0; i < arguments.length; i++) {
console.log("There's no stopping " + arguments[i]);
}
}
superHeroes('UberMan', 'Exceptional Woman', 'The Hunk');
However, in dart, that code will not run. Is there a way to do the same thing in dart? If not, is this something that is on the roadmap?
You can't do that for now.
I don't really know if varargs will come back - they were there some times ago but have been removed.
However it is possible to emulate varargs with Emulating functions. See the below code snippet.
typedef OnCall = dynamic Function(List arguments);
class VarargsFunction {
VarargsFunction(this._onCall);
final OnCall _onCall;
noSuchMethod(Invocation invocation) {
if (!invocation.isMethod || invocation.namedArguments.isNotEmpty)
super.noSuchMethod(invocation);
final arguments = invocation.positionalArguments;
return _onCall(arguments);
}
}
main() {
final superHeroes = VarargsFunction((arguments) {
for (final superHero in arguments) {
print("There's no stopping ${superHero}");
}
}) as dynamic;
superHeroes('UberMan', 'Exceptional Woman', 'The Hunk');
}
Dart does indirectly support var-args as long as you aren't too much into syntactic brevity.
void testFunction([List<dynamic> args=[]])
{
for(dynamic arg:args)
{
// Handle each arg...
}
}
testFunction([0, 1, 2, 3, 4, 5, 6]);
testFunction();
testFunction([0, 1, 2]);
Note: You can do the same thing with named parameters, but you'll have to handle things internally, just in case if the user (of that function; which could be you) decides to not pass any value to that named parameter.
I would like to thank #Ladicek for indirectly letting me know that a word like brevity exists in English.
This version:
Works with both positional and keyword arguments.
Supports typing of the return value.
Works with modern Dart.
typedef VarArgsCallback = void Function(List<dynamic> args, Map<String, dynamic> kwargs);
class VarArgsFunction {
final VarArgsCallback callback;
static var _offset = 'Symbol("'.length;
VarArgsFunction(this.callback);
void call() => callback([], {});
#override
dynamic noSuchMethod(Invocation inv) {
return callback(
inv.positionalArguments,
inv.namedArguments.map(
(_k, v) {
var k = _k.toString();
return MapEntry(k.substring(_offset, k.length - 2), v);
},
),
);
}
}
void main() {
dynamic myFunc = VarArgsFunction((args, kwargs) {
print('Got args: $args, kwargs: $kwargs');
});
myFunc(1, 2, x: true, y: false); // Got args: [1, 2], kwargs: {x: true, y: false}
}
Thanks, Alexandre for your answer!
I played around a little with Alexandre Ardhuin's answer and found that we can tweak a couple of things to make this work in the current version of Dart:
class VarArgsClass {
noSuchMethod(InvocationMirror invocation) {
if (invocation.memberName == 'superheroes') {
this.superheroes(invocation.positionalArguments);
}
}
void superheroes(List<String> heroNames) {
for (final superHero in heroNames) {
print("There's no stopping ${superHero}!");
}
}
}
main() {
new VarArgsClass().superheroes('UberMan', 'Exceptional Woman', 'The Hunk');
}
This has lots of problems, including:
A warning is generated wherever you call superheroes() because the signature doesn't match your parameters.
More manual checking would need to be done to make sure the list of arguments passed to superheroes is really a List<String>.
Needing to check the member name in noSuchMethod() makes it more likely you'll forget to change the 'superheroes' string if you change the method name.
Reflection makes the code path harder to trace.
BUT if you are fine with all of those issues, then this gets the job done.
If you are really into syntactic brevity, just declare a function/method with say 10 optional positional parameters and be done. It's unlikely someone will call that with more than 10 arguments.
If it sounds like a hack, that's because it is a hack. But I've seen the Dart team doing the same :-)
For example:
void someMethod(arg0, [arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9]) {
final args = [arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9];
args.removeWhere((value) => value == null);
/* do something the the args List */
print(args);
}
For the example you've written, I think you're best off using a list. Sorry about that!
I'm looking at dartbug.com, but I don't see a feature request for this. You're definitely welcome to create one!