RxDart, mapping each item of a list to another object coming from a never ending stream
I've been trying to find a nice way of doing this but I had no luck.
Here is a simplified version of the problem:
import 'package:rxdart/rxdart.dart';
/// Input a list of integers [0,1,2,3,4]
/// map each of those integers to the corresponding index in the map
/// if the map updates, the output should update too.
///
/// The output should be a list of Strings:
/// ["Hi from 1", "Hi from 2"; "Hi from 3", "Hi from 4", "Hi from 5"]
BehaviorSubject<Map<int, String>> subject = BehaviorSubject(
seedValue: {
1: "Hi from 1",
2: "Hi from 2",
3: "Hi from 3",
4: "Hi from 4",
5: "Hi from 5",
}
);
void main() {
Observable.fromIterable([1, 2, 3, 4, 5])
.flatMap((index) => subject.stream.map((map) => map[index]))
.toList().asObservable()
.listen((data) {
print("List of data incoming $data");
});
}
When running this, nothing is printed. This is because the subject never completes and thus the toList()
never finishes building the list.
Replacing the subject with for example an Observable.just(index + 2)
does work because the Observable completes and the toList()
is able to collect them.
But the intended behavior is that the example should emit the new list of strings each time the subject is changed.
Any help would be appreciated,
Thanks!
dart stream rxdart
add a comment |
I've been trying to find a nice way of doing this but I had no luck.
Here is a simplified version of the problem:
import 'package:rxdart/rxdart.dart';
/// Input a list of integers [0,1,2,3,4]
/// map each of those integers to the corresponding index in the map
/// if the map updates, the output should update too.
///
/// The output should be a list of Strings:
/// ["Hi from 1", "Hi from 2"; "Hi from 3", "Hi from 4", "Hi from 5"]
BehaviorSubject<Map<int, String>> subject = BehaviorSubject(
seedValue: {
1: "Hi from 1",
2: "Hi from 2",
3: "Hi from 3",
4: "Hi from 4",
5: "Hi from 5",
}
);
void main() {
Observable.fromIterable([1, 2, 3, 4, 5])
.flatMap((index) => subject.stream.map((map) => map[index]))
.toList().asObservable()
.listen((data) {
print("List of data incoming $data");
});
}
When running this, nothing is printed. This is because the subject never completes and thus the toList()
never finishes building the list.
Replacing the subject with for example an Observable.just(index + 2)
does work because the Observable completes and the toList()
is able to collect them.
But the intended behavior is that the example should emit the new list of strings each time the subject is changed.
Any help would be appreciated,
Thanks!
dart stream rxdart
toList()
won't execute when the stream is never ending. Perhaps all you need ishttps://api.dartlang.org/stable/2.1.0/dart-async/Stream/map.html with
stream.map(...).listen(...)`
– Günter Zöchbauer
Nov 26 '18 at 9:55
I'd saycombineLatest
instead
– Rémi Rousselet
Nov 26 '18 at 9:59
add a comment |
I've been trying to find a nice way of doing this but I had no luck.
Here is a simplified version of the problem:
import 'package:rxdart/rxdart.dart';
/// Input a list of integers [0,1,2,3,4]
/// map each of those integers to the corresponding index in the map
/// if the map updates, the output should update too.
///
/// The output should be a list of Strings:
/// ["Hi from 1", "Hi from 2"; "Hi from 3", "Hi from 4", "Hi from 5"]
BehaviorSubject<Map<int, String>> subject = BehaviorSubject(
seedValue: {
1: "Hi from 1",
2: "Hi from 2",
3: "Hi from 3",
4: "Hi from 4",
5: "Hi from 5",
}
);
void main() {
Observable.fromIterable([1, 2, 3, 4, 5])
.flatMap((index) => subject.stream.map((map) => map[index]))
.toList().asObservable()
.listen((data) {
print("List of data incoming $data");
});
}
When running this, nothing is printed. This is because the subject never completes and thus the toList()
never finishes building the list.
Replacing the subject with for example an Observable.just(index + 2)
does work because the Observable completes and the toList()
is able to collect them.
But the intended behavior is that the example should emit the new list of strings each time the subject is changed.
Any help would be appreciated,
Thanks!
dart stream rxdart
I've been trying to find a nice way of doing this but I had no luck.
Here is a simplified version of the problem:
import 'package:rxdart/rxdart.dart';
/// Input a list of integers [0,1,2,3,4]
/// map each of those integers to the corresponding index in the map
/// if the map updates, the output should update too.
///
/// The output should be a list of Strings:
/// ["Hi from 1", "Hi from 2"; "Hi from 3", "Hi from 4", "Hi from 5"]
BehaviorSubject<Map<int, String>> subject = BehaviorSubject(
seedValue: {
1: "Hi from 1",
2: "Hi from 2",
3: "Hi from 3",
4: "Hi from 4",
5: "Hi from 5",
}
);
void main() {
Observable.fromIterable([1, 2, 3, 4, 5])
.flatMap((index) => subject.stream.map((map) => map[index]))
.toList().asObservable()
.listen((data) {
print("List of data incoming $data");
});
}
When running this, nothing is printed. This is because the subject never completes and thus the toList()
never finishes building the list.
Replacing the subject with for example an Observable.just(index + 2)
does work because the Observable completes and the toList()
is able to collect them.
But the intended behavior is that the example should emit the new list of strings each time the subject is changed.
Any help would be appreciated,
Thanks!
dart stream rxdart
dart stream rxdart
asked Nov 26 '18 at 9:44
NorbertNorbert
5327
5327
toList()
won't execute when the stream is never ending. Perhaps all you need ishttps://api.dartlang.org/stable/2.1.0/dart-async/Stream/map.html with
stream.map(...).listen(...)`
– Günter Zöchbauer
Nov 26 '18 at 9:55
I'd saycombineLatest
instead
– Rémi Rousselet
Nov 26 '18 at 9:59
add a comment |
toList()
won't execute when the stream is never ending. Perhaps all you need ishttps://api.dartlang.org/stable/2.1.0/dart-async/Stream/map.html with
stream.map(...).listen(...)`
– Günter Zöchbauer
Nov 26 '18 at 9:55
I'd saycombineLatest
instead
– Rémi Rousselet
Nov 26 '18 at 9:59
toList()
won't execute when the stream is never ending. Perhaps all you need is https://api.dartlang.org/stable/2.1.0/dart-async/Stream/map.html with
stream.map(...).listen(...)`– Günter Zöchbauer
Nov 26 '18 at 9:55
toList()
won't execute when the stream is never ending. Perhaps all you need is https://api.dartlang.org/stable/2.1.0/dart-async/Stream/map.html with
stream.map(...).listen(...)`– Günter Zöchbauer
Nov 26 '18 at 9:55
I'd say
combineLatest
instead– Rémi Rousselet
Nov 26 '18 at 9:59
I'd say
combineLatest
instead– Rémi Rousselet
Nov 26 '18 at 9:59
add a comment |
2 Answers
2
active
oldest
votes
You probably want to use combineLatest instead
BehaviorSubject<Map<int, String>> subject = BehaviorSubject(seedValue: {
1: "Hi from 1",
2: "Hi from 2",
3: "Hi from 3",
4: "Hi from 4",
5: "Hi from 5",
});
void main() {
Observable.combineLatest2(
Observable.just([1, 2, 3, 4, 5]), subject.stream, combiner)
..listen(
(data) {
print("List of data incoming $data");
},
);
}
Iterable<String> combiner(List<int> indexes, Map<int, String> map) {
return indexes.map((index) => map[index]);
}
This works great for this example! Unfortunately, in the app I'm working on I have aStream<User> getUser(String id)
instead of one single observable containing all the users and therefore combineLatest doesn't working (because there can only be a maximum of 9 streams).
– Norbert
Nov 26 '18 at 10:37
I don't quite get your issue tbh
– Rémi Rousselet
Nov 26 '18 at 10:43
add a comment |
Edit: shortly after posting this I realized that it completely depends on how the data is exposed:
If you have a method which has a signature like Observable<String> getStringForInt(int number)
and you have to call it for every item in the list, my solution is the one for you. Note if the above method always subscribes to the same stream, changing that stream will result in multiple emissions (because combineLatest updates every item).
However, if you have access to the whole data container (like a Map
Original Answer
Ok, it turns out, it wasn't quite possible to achieve that with the implementation of rxDart.
The combineLatest
constructor only supported up to 9 streams.
But since then, combineLatest with n-streams has been implemented and the solution to this problem would look something like this:
Map<int, BehaviorSubject<String>> subject2 = {
1: BehaviorSubject<String>(seedValue: "Subject 1"),
2: BehaviorSubject<String>(seedValue: "Subject 2"),
3: BehaviorSubject<String>(seedValue: "Subject 3"),
4: BehaviorSubject<String>(seedValue: "Subject 4"),
5: BehaviorSubject<String>(seedValue: "Subject 5"),
};
void main() async {
Observable.fromIterable([1, 2, 3, 4, 5])
.toList().asObservable()
.flatMap((numbers) =>
Observable.combineLatest<String, List<String>>(numbers.map((index) => subject2[index]), (strings) => strings))
.listen((data) {
print("List of data incoming $data");
});
await Future.delayed(Duration(seconds: 2));
subject2[1].add("I'm 42 now");
}
This will print:
List of data incoming [Subject 1, Subject 2, Subject 3, Subject 4, Subject 5]
List of data incoming [I'm 42 now, Subject 2, Subject 3, Subject 4, Subject 5]
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53478354%2frxdart-mapping-each-item-of-a-list-to-another-object-coming-from-a-never-ending%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
You probably want to use combineLatest instead
BehaviorSubject<Map<int, String>> subject = BehaviorSubject(seedValue: {
1: "Hi from 1",
2: "Hi from 2",
3: "Hi from 3",
4: "Hi from 4",
5: "Hi from 5",
});
void main() {
Observable.combineLatest2(
Observable.just([1, 2, 3, 4, 5]), subject.stream, combiner)
..listen(
(data) {
print("List of data incoming $data");
},
);
}
Iterable<String> combiner(List<int> indexes, Map<int, String> map) {
return indexes.map((index) => map[index]);
}
This works great for this example! Unfortunately, in the app I'm working on I have aStream<User> getUser(String id)
instead of one single observable containing all the users and therefore combineLatest doesn't working (because there can only be a maximum of 9 streams).
– Norbert
Nov 26 '18 at 10:37
I don't quite get your issue tbh
– Rémi Rousselet
Nov 26 '18 at 10:43
add a comment |
You probably want to use combineLatest instead
BehaviorSubject<Map<int, String>> subject = BehaviorSubject(seedValue: {
1: "Hi from 1",
2: "Hi from 2",
3: "Hi from 3",
4: "Hi from 4",
5: "Hi from 5",
});
void main() {
Observable.combineLatest2(
Observable.just([1, 2, 3, 4, 5]), subject.stream, combiner)
..listen(
(data) {
print("List of data incoming $data");
},
);
}
Iterable<String> combiner(List<int> indexes, Map<int, String> map) {
return indexes.map((index) => map[index]);
}
This works great for this example! Unfortunately, in the app I'm working on I have aStream<User> getUser(String id)
instead of one single observable containing all the users and therefore combineLatest doesn't working (because there can only be a maximum of 9 streams).
– Norbert
Nov 26 '18 at 10:37
I don't quite get your issue tbh
– Rémi Rousselet
Nov 26 '18 at 10:43
add a comment |
You probably want to use combineLatest instead
BehaviorSubject<Map<int, String>> subject = BehaviorSubject(seedValue: {
1: "Hi from 1",
2: "Hi from 2",
3: "Hi from 3",
4: "Hi from 4",
5: "Hi from 5",
});
void main() {
Observable.combineLatest2(
Observable.just([1, 2, 3, 4, 5]), subject.stream, combiner)
..listen(
(data) {
print("List of data incoming $data");
},
);
}
Iterable<String> combiner(List<int> indexes, Map<int, String> map) {
return indexes.map((index) => map[index]);
}
You probably want to use combineLatest instead
BehaviorSubject<Map<int, String>> subject = BehaviorSubject(seedValue: {
1: "Hi from 1",
2: "Hi from 2",
3: "Hi from 3",
4: "Hi from 4",
5: "Hi from 5",
});
void main() {
Observable.combineLatest2(
Observable.just([1, 2, 3, 4, 5]), subject.stream, combiner)
..listen(
(data) {
print("List of data incoming $data");
},
);
}
Iterable<String> combiner(List<int> indexes, Map<int, String> map) {
return indexes.map((index) => map[index]);
}
answered Nov 26 '18 at 10:00
Rémi RousseletRémi Rousselet
29.3k36592
29.3k36592
This works great for this example! Unfortunately, in the app I'm working on I have aStream<User> getUser(String id)
instead of one single observable containing all the users and therefore combineLatest doesn't working (because there can only be a maximum of 9 streams).
– Norbert
Nov 26 '18 at 10:37
I don't quite get your issue tbh
– Rémi Rousselet
Nov 26 '18 at 10:43
add a comment |
This works great for this example! Unfortunately, in the app I'm working on I have aStream<User> getUser(String id)
instead of one single observable containing all the users and therefore combineLatest doesn't working (because there can only be a maximum of 9 streams).
– Norbert
Nov 26 '18 at 10:37
I don't quite get your issue tbh
– Rémi Rousselet
Nov 26 '18 at 10:43
This works great for this example! Unfortunately, in the app I'm working on I have a
Stream<User> getUser(String id)
instead of one single observable containing all the users and therefore combineLatest doesn't working (because there can only be a maximum of 9 streams).– Norbert
Nov 26 '18 at 10:37
This works great for this example! Unfortunately, in the app I'm working on I have a
Stream<User> getUser(String id)
instead of one single observable containing all the users and therefore combineLatest doesn't working (because there can only be a maximum of 9 streams).– Norbert
Nov 26 '18 at 10:37
I don't quite get your issue tbh
– Rémi Rousselet
Nov 26 '18 at 10:43
I don't quite get your issue tbh
– Rémi Rousselet
Nov 26 '18 at 10:43
add a comment |
Edit: shortly after posting this I realized that it completely depends on how the data is exposed:
If you have a method which has a signature like Observable<String> getStringForInt(int number)
and you have to call it for every item in the list, my solution is the one for you. Note if the above method always subscribes to the same stream, changing that stream will result in multiple emissions (because combineLatest updates every item).
However, if you have access to the whole data container (like a Map
Original Answer
Ok, it turns out, it wasn't quite possible to achieve that with the implementation of rxDart.
The combineLatest
constructor only supported up to 9 streams.
But since then, combineLatest with n-streams has been implemented and the solution to this problem would look something like this:
Map<int, BehaviorSubject<String>> subject2 = {
1: BehaviorSubject<String>(seedValue: "Subject 1"),
2: BehaviorSubject<String>(seedValue: "Subject 2"),
3: BehaviorSubject<String>(seedValue: "Subject 3"),
4: BehaviorSubject<String>(seedValue: "Subject 4"),
5: BehaviorSubject<String>(seedValue: "Subject 5"),
};
void main() async {
Observable.fromIterable([1, 2, 3, 4, 5])
.toList().asObservable()
.flatMap((numbers) =>
Observable.combineLatest<String, List<String>>(numbers.map((index) => subject2[index]), (strings) => strings))
.listen((data) {
print("List of data incoming $data");
});
await Future.delayed(Duration(seconds: 2));
subject2[1].add("I'm 42 now");
}
This will print:
List of data incoming [Subject 1, Subject 2, Subject 3, Subject 4, Subject 5]
List of data incoming [I'm 42 now, Subject 2, Subject 3, Subject 4, Subject 5]
add a comment |
Edit: shortly after posting this I realized that it completely depends on how the data is exposed:
If you have a method which has a signature like Observable<String> getStringForInt(int number)
and you have to call it for every item in the list, my solution is the one for you. Note if the above method always subscribes to the same stream, changing that stream will result in multiple emissions (because combineLatest updates every item).
However, if you have access to the whole data container (like a Map
Original Answer
Ok, it turns out, it wasn't quite possible to achieve that with the implementation of rxDart.
The combineLatest
constructor only supported up to 9 streams.
But since then, combineLatest with n-streams has been implemented and the solution to this problem would look something like this:
Map<int, BehaviorSubject<String>> subject2 = {
1: BehaviorSubject<String>(seedValue: "Subject 1"),
2: BehaviorSubject<String>(seedValue: "Subject 2"),
3: BehaviorSubject<String>(seedValue: "Subject 3"),
4: BehaviorSubject<String>(seedValue: "Subject 4"),
5: BehaviorSubject<String>(seedValue: "Subject 5"),
};
void main() async {
Observable.fromIterable([1, 2, 3, 4, 5])
.toList().asObservable()
.flatMap((numbers) =>
Observable.combineLatest<String, List<String>>(numbers.map((index) => subject2[index]), (strings) => strings))
.listen((data) {
print("List of data incoming $data");
});
await Future.delayed(Duration(seconds: 2));
subject2[1].add("I'm 42 now");
}
This will print:
List of data incoming [Subject 1, Subject 2, Subject 3, Subject 4, Subject 5]
List of data incoming [I'm 42 now, Subject 2, Subject 3, Subject 4, Subject 5]
add a comment |
Edit: shortly after posting this I realized that it completely depends on how the data is exposed:
If you have a method which has a signature like Observable<String> getStringForInt(int number)
and you have to call it for every item in the list, my solution is the one for you. Note if the above method always subscribes to the same stream, changing that stream will result in multiple emissions (because combineLatest updates every item).
However, if you have access to the whole data container (like a Map
Original Answer
Ok, it turns out, it wasn't quite possible to achieve that with the implementation of rxDart.
The combineLatest
constructor only supported up to 9 streams.
But since then, combineLatest with n-streams has been implemented and the solution to this problem would look something like this:
Map<int, BehaviorSubject<String>> subject2 = {
1: BehaviorSubject<String>(seedValue: "Subject 1"),
2: BehaviorSubject<String>(seedValue: "Subject 2"),
3: BehaviorSubject<String>(seedValue: "Subject 3"),
4: BehaviorSubject<String>(seedValue: "Subject 4"),
5: BehaviorSubject<String>(seedValue: "Subject 5"),
};
void main() async {
Observable.fromIterable([1, 2, 3, 4, 5])
.toList().asObservable()
.flatMap((numbers) =>
Observable.combineLatest<String, List<String>>(numbers.map((index) => subject2[index]), (strings) => strings))
.listen((data) {
print("List of data incoming $data");
});
await Future.delayed(Duration(seconds: 2));
subject2[1].add("I'm 42 now");
}
This will print:
List of data incoming [Subject 1, Subject 2, Subject 3, Subject 4, Subject 5]
List of data incoming [I'm 42 now, Subject 2, Subject 3, Subject 4, Subject 5]
Edit: shortly after posting this I realized that it completely depends on how the data is exposed:
If you have a method which has a signature like Observable<String> getStringForInt(int number)
and you have to call it for every item in the list, my solution is the one for you. Note if the above method always subscribes to the same stream, changing that stream will result in multiple emissions (because combineLatest updates every item).
However, if you have access to the whole data container (like a Map
Original Answer
Ok, it turns out, it wasn't quite possible to achieve that with the implementation of rxDart.
The combineLatest
constructor only supported up to 9 streams.
But since then, combineLatest with n-streams has been implemented and the solution to this problem would look something like this:
Map<int, BehaviorSubject<String>> subject2 = {
1: BehaviorSubject<String>(seedValue: "Subject 1"),
2: BehaviorSubject<String>(seedValue: "Subject 2"),
3: BehaviorSubject<String>(seedValue: "Subject 3"),
4: BehaviorSubject<String>(seedValue: "Subject 4"),
5: BehaviorSubject<String>(seedValue: "Subject 5"),
};
void main() async {
Observable.fromIterable([1, 2, 3, 4, 5])
.toList().asObservable()
.flatMap((numbers) =>
Observable.combineLatest<String, List<String>>(numbers.map((index) => subject2[index]), (strings) => strings))
.listen((data) {
print("List of data incoming $data");
});
await Future.delayed(Duration(seconds: 2));
subject2[1].add("I'm 42 now");
}
This will print:
List of data incoming [Subject 1, Subject 2, Subject 3, Subject 4, Subject 5]
List of data incoming [I'm 42 now, Subject 2, Subject 3, Subject 4, Subject 5]
edited Dec 14 '18 at 12:29
answered Dec 14 '18 at 12:05
NorbertNorbert
5327
5327
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53478354%2frxdart-mapping-each-item-of-a-list-to-another-object-coming-from-a-never-ending%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
toList()
won't execute when the stream is never ending. Perhaps all you need ishttps://api.dartlang.org/stable/2.1.0/dart-async/Stream/map.html with
stream.map(...).listen(...)`– Günter Zöchbauer
Nov 26 '18 at 9:55
I'd say
combineLatest
instead– Rémi Rousselet
Nov 26 '18 at 9:59