package learnrxjava; import learnrxjava.types.JSON; import learnrxjava.types.Movies; import rx.Observable; public class ObservableSolutions extends ObservableExercises { /** * Return an Observable that emits a single value "Hello World" * * @return "Hello World!" */ public Observable<String> exerciseHello() { return Observable.just("Hello World!"); } /** * Transform the incoming Observable from "Hello" to "Hello [Name]" where [Name] is your name. * * @param "Hello Name!" */ public Observable<String> exerciseMap(Observable<String> hello) { return hello.map(t -> t + " Ben!"); } /** * Given a stream of numbers, choose the even ones and return a stream like: * <p> * 2-Even * 4-Even * 6-Even */ public Observable<String> exerciseFilterMap(Observable<Integer> nums) { return nums.filter(i -> i % 2 == 0).map(i -> i + "-Even"); } /** * Flatten out all video in the stream of Movies into a stream of videoIDs * * @param movieLists * @return Observable of Integers of Movies.videos.id */ public Observable<Integer> exerciseConcatMap(Observable<Movies> movies) { return movies.<Integer> concatMap(ml -> { return ml.videos.map(v -> v.id); }); } /** * Flatten out all video in the stream of Movies into a stream of videoIDs * * Use flatMap this time instead of concatMap. In Observable streams * it is almost always flatMap that is wanted, not concatMap as flatMap * uses merge instead of concat and allows multiple concurrent streams * whereas concat only does one at a time. * * We'll see more about this later when we add concurrency. * * @param movieLists * @return Observable of Integers of Movies.videos.id */ public Observable<Integer> exerciseFlatMap(Observable<Movies> movies) { return movies.<Integer> flatMap(ml -> { return ml.videos.map(v -> v.id); }); } /** * Retrieve the largest number. * * Use reduce to select the maximum value in a list of numbers. */ public Observable<Integer> exerciseReduce(Observable<Integer> nums) { return nums.reduce((max, item) -> { if (item > max) { return item; } else { return max; } }); } /** * Retrieve the id, title, and smallest box art url for every video. * * Now let's try combining reduce() with our other functions to build more complex queries. * * This is a variation of the problem we solved earlier, where we retrieved the url of the boxart with a * width of 150px. This time we'll use reduce() instead of filter() to retrieve the _smallest_ box art in * the boxarts list. * * See Exercise 19 of ComposableListExercises */ public Observable<JSON> exerciseMovie(Observable<Movies> movies) { return movies.flatMap(ml -> { return ml.videos.<JSON> flatMap(v -> { return v.boxarts.reduce((max, box) -> { int maxSize = max.height * max.width; int boxSize = box.height * box.width; if (boxSize < maxSize) { return box; } else { return max; } }).map(maxBoxart -> { return json("id", v.id, "title", v.title, "boxart", maxBoxart.url); }); }); }); } /** * Combine 2 streams into pairs using zip. * * a -> "one", "two", "red", "blue" * b -> "fish", "fish", "fish", "fish" * output -> "one fish", "two fish", "red fish", "blue fish" */ public Observable<String> exerciseZip(Observable<String> a, Observable<String> b) { return Observable.zip(a, b, (x, y) -> x + " " + y); } /** * Don't modify any values in the stream but do handle the error * and replace it with "default-value". */ public Observable<String> handleError(Observable<String> data) { return data.onErrorResumeNext(Observable.just("default-value")); } /** * The data stream fails intermittently so return the stream * with retry capability. */ public Observable<String> retry(Observable<String> data) { return data.retry(); } // This function can be used to build JSON objects within an expression private static JSON json(Object... keyOrValue) { JSON json = new JSON(); for (int counter = 0; counter < keyOrValue.length; counter += 2) { json.put((String) keyOrValue[counter], keyOrValue[counter + 1]); } return json; } }