Reputation: 1240
I have list coming back from a REST endpoint. I need to break that list down into categories (category is an item in each entry of the list). Individual categories will be written to a cache for faster lookup later.
I didn't know if I could .map() the entries and supply multiple filter() or some type of case statement to put the category entries in the right bucket.
Does something like this sound reasonable to implement with rxJava?
UPDATE: Non-working version
private Map<String, List<VideoMetadataInfoEntity>> buildCategories( Observable<List<VideoMetadataInfoEntity>> videoList ) {
Map<String, List<VideoMetadataInfoEntity>> categoryMap = new HashMap<>();
videoList
.flatMap( Observable::from )
.subscribe( videoMetadataInfoEntity -> mapCategory(videoMetadataInfoEntity, categoryMap ) );
Observable.just( categoryMap )
.doOnNext( saveCategoriesToCacheAction );
return categoryMap;
}
These fire in sequence, however, and this is my understanding, the second observable is not sending anything the saveCategoriesToCacheAction since it hasn't subscribed to the result of the first observable.
I am starting to think I should modify my cache strategy. The list will always have all the details. The service doesn't provide me a subset that I can use for listing and then another call to get the full details. It is either full list or full details for one item. It might be a better approach to just cache each one individually and into their own category caches right now. I was trying to do the map so that this network call could return the requested category, but subsequent calls would come from the cache, until such time as the cache has expired and a new network call refreshes it.
Upvotes: 3
Views: 6767
Reputation: 303
My solution is:
Observable.range(1, 20)
.groupBy(number -> number % 2)
.flatMap(groupedObservable -> groupedObservable.toList())
.toMap(list -> list.get(0) % 2);
As a result I have [{0=[2, 4, 6, 8, 10, 12, 14, 16, 18, 20], 1=[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]}]
Explanation:
Upvotes: 3
Reputation: 2390
Generally grouping of items can be achieved using a groupBy operator (for more information about it visit this page).
Map<Integer, List<Integer>> groupedValues = new HashMap<>(4);
Observable.range(1, 20)
.groupBy(i -> i % 2, i -> i)
.subscribe(go -> {
List<Integer> groupValues = new ArrayList<>();
groupedValues.put(go.getKey(), groupValues);
go.subscribe(t -> add(t, groupValues));
});
How it works:
range
method)groupBy
method, after this method you operate on GroupedObservable) onNext
) separate observables that will contain grouped items and the key they were grouped by.Remember to either subscribe to the grouped observables or issue take(0)
on them if their content does not interest you to prevent memory leaks.
I am not sure whether it is the most efficient way or not and would welcome some input about this solution.
Upvotes: 0
Reputation: 2099
RxJava is more for asynchronous message processing, but as it also espouses functional programming principles it could be used as a poor man's stream api. If you are using Java 8 consider using streams to do this job, but as you are asking this question I assume you are using Java 7.
To do what you want you could try (forgive the lambda, substitute it with an anonymous inner class if you are not using Retrolambda):
Observable.from(list).subscribe(item -> groupItemInCategoryBucket(item));
where groupItemInCategoryBucket
is your method that contains the switch statement or whatever other way you have of caching the items.
Please note that this is the equivalent of a for loop, and although it is idiomatic to use this style in many other nice languages, a lot of Java developers might be a bit puzzled when they see this code.
Upvotes: 0