You will want to call Future.wait<Foo>
on each of the inner List<Future<Foo>>
s. Each of those will return a Future<List<Foo>>
; collect those Future
s into their own list, and then use Future.wait
again on that.
As you mentioned, the tricky part is assigning to results to the desired locations. You can use Future.then
to register a completion callback for each of the Future<List<Foo>>
s that assigns the resulting List<Foo>
to the new Map
. This is one situation where mixing Future.then
with await
is a little bit more straightforward than using just await
. (It's still possible with await
, but it's more awkward.)
For example:
import 'dart:async';
/// Randomized delays to test correctness.
final delays = <int>[for (var i = 0; i < 9; i += 1) i]..shuffle();
/// Returns `result` after a randomized delay.
Future<int> f(int result) async {
var index = result - 1;
assert(index >= 0);
assert(index < delays.length);
await Future.delayed(Duration(seconds: delays[result - 1]));
return result;
}
var map = <String, List<Future<int>>>{
'foo': [f(1), f(2), f(3)],
'bar': [f(4), f(5), f(6)],
'baz': [f(7), f(8), f(9)],
};
Future<void> main() async {
var newMap = <String, List<int>>{};
await Future.wait<void>([
for (var key in map.keys)
Future.wait<int>(map[key]!).then((list) => newMap[key] = list),
]);
print(newMap); // Prints: {foo: [1, 2, 3], bar: [4, 5, 6], baz: [7, 8, 9]}
}
Note that the above does not guarantee that newMap
preserves the order of keys in the Map
. If you care about that, then an easy way to preserve the key order is to pre-add them to the new Map
:
var newMap = {for (var key in map.keys) key: <int>[]};
or alternatively, remove and re-add them in the desired order afterward:
for (var key in map.keys) {
newMap[key] = newMap.remove(key)!;
}