forked from jhusain/learnrxjava
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathComposableList.java
More file actions
1245 lines (1061 loc) · 53.1 KB
/
ComposableList.java
File metadata and controls
1245 lines (1061 loc) · 53.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package learnrxjava;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
/**
*
*/
public class ComposableList<T> extends ArrayList<T> {
public static <T> ComposableList<T> of(T... args) {
ComposableList<T> results = new ComposableList<T>();
for (T value : args) {
results.add(value);
}
return results;
}
public static class JSON extends HashMap<String, Object> {
};
public 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;
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
(new ComposableList()).exercise1();
}
/*
Traversing a List
*/
public void exercise1() {
ComposableList<String> names = ComposableList.of("Ben", "Jafar", "Matt", "Priya", "Brian");
for (String name : names) {
System.out.println(name);
}
}
/*
Traversing a ComposableList
Unlike Lists and other collections that implement the Iterable
interface, you can _not_ use Java’s for each loop to traverse a Stream.
Instead Stream provides a forEach method to which you pass a lambda. The
ComposableList invokes your lambda once for every item in the stream, and passes
the item to the lambda each time. To match the Stream interface, our
ComposableList also has a forEach method (inherited from ArrayList). Let's
solve the same problem we solved above, but this time we'll use forEach()
instead of the Java for each loop.
Note that the code is very similar, and we get the same result whether we
are using the Java for each syntax or the forEach method on the ComposableList.
Note: This exercise is already finished, so just move on.
*/
public void exercise2() {
ComposableList<String> names = ComposableList.of("Ben", "Jafar", "Matt", "Priya", "Brian");
names.forEach(name -> {
System.out.println(name);
});
}
/*
Projecting Lists
Applying a function to a value and creating a new value is called a
projection. To project one List into another, we apply a projection
function to each item in the List and collect the results in a new List.
exercise 3: Project a list of videos into a list of {id,title} JSON
objects using forEach
For each video, add a projected {id, title} json to the videoAndTitlePairs
List. You can create JSON objects like this:
*/
class Bookmark {
public int id;
public int offset;
public Bookmark(int id, int offset) {
this.id = id;
this.offset = offset;
}
}
class InterestingMoment {
String type;
int time;
public InterestingMoment(String type, int time) {
this.type = type;
this.time = time;
}
}
class Video {
public int id;
public String title;
public double rating;
private ComposableList<Bookmark> bookmarks;
private ComposableList<BoxArt> boxarts;
private ComposableList<InterestingMoment> interestingMoments;
public Video(int id, String title, double rating) {
this.id = id;
this.title = title;
this.rating = rating;
}
public Video(int id, String title, double rating, ComposableList<Bookmark> bookmarks, ComposableList<BoxArt> boxarts) {
this(id, title, rating);
this.bookmarks = bookmarks;
this.boxarts = boxarts;
}
public Video(int id, String title, double rating, ComposableList<Bookmark> bookmarks, ComposableList<BoxArt> boxarts, ComposableList<InterestingMoment> interestingMoments) {
this(id, title, rating);
this.bookmarks = bookmarks;
this.boxarts = boxarts;
this.interestingMoments = interestingMoments;
}
}
public ComposableList<JSON> exercise3() {
ComposableList<Video> newReleases = ComposableList.of(
new Video(70111470, "Die Hard", 4.0),
new Video(654356453, "Bad Boys", 5.0),
new Video(65432445, "The Chamber", 4.0),
new Video(675465, "Fracture", 5.0));
ComposableList<JSON> videoAndTitlePairs = new ComposableList<JSON>();
// ------------ INSERT CODE HERE! -----------------------------------
// Use the forEach function to accumulate {id, title} JSON from each
// video. Put the results into the videoAndTitlePairs list using the
// List's add method.
// Example: videoAndTitlePairs.add(json("id", 5, "name", "Die Hard"));
// ------------ INSERT CODE HERE! -----------------------------------
// **************ANSWER START***************//
// for(Video video: newReleases) {
// videoAndTitlePairs.add(json("id", video.id, "title", video.title));
// }
// **************ANSWER END***************//
return videoAndTitlePairs;
}
/*
All list projections share two operations in common:
1. Traverse the source list
2. Add each item's projected value to a new list
Why not abstract away how these operations are carried out?
exercise 4: Implement map() for List
If the List interface had a map() method, it would make projections easier.
The map method accepts the projection function to be applied to each item
in the source List, and returns a List of the projected results.
Ideally we'd be able to call ComposableList.of(1,2,3).map(x -> x + 1) to create
a new List with a value of ComposableList.of(2,3,4). Unfortunately List doesn't
have a map method and there's no way for us to add one. However we _can_
define a static method map that accepts a list, a projection function, and
returns the translated list.
map(ComposableList.of(1,2,3), x -> x + 1) is equivalent to ComposableList.of(2,3,4)
*/
public <R> ComposableList<R> map(Function<T, R> projectionFunction) {
ComposableList<R> results = new ComposableList<R>();
for (T itemInList : this) {
// ------------ INSERT CODE HERE! ----------------------------
// Apply the projectionFunction to each item in the list and add
// each result to the results list.
// Note that you can apply a projectionFunction to a value like this:
// projectionFunction.apply(5)
// ------------ INSERT CODE HERE! ----------------------------
// **************ANSWER START***************//
// results.add(projectionFunction.apply(itemInList));
// **************ANSWER END***************//
}
return results;
}
/*
exercise 5: Use map() to project a ComposableList of videos into a stream of {id,title} JSON
Now let's use our map method to solve the previous problem.
ComposableList.of(1,2,3).map(x -> x + 1) is equivalent to writing ComposableList.of(2,3,4)
Let's repeat exercise 3 and collect {id, title} pairs for each video in newReleases, but this time we'll use the map method on ComposableLists instead of a for each loop on Lists
*/
public ComposableList<JSON> exercise5() {
ComposableList<Video> newReleases = ComposableList.of(
new Video(70111470, "Die Hard", 4.0),
new Video(654356453, "Bad Boys", 5.0),
new Video(65432445, "The Chamber", 4.0),
new Video(675465, "Fracture", 5.0));
// ------------ INSERT CODE HERE! -----------------------------------
// Use the map function to accumulate {id, title} json from each video.
// Uncomment the code below and finish the expression
// return videoAndTitlePairs.map(video ->
// **************ANSWER START***************//
// return newReleases.map(video -> json("id", video.id, "title", video.title));
// **************ANSWER END***************//
throw new UnsupportedOperationException("Not implemented yet.");
}
/*
Notice that map allows us to specify what projection we want to apply to a list, but hides how the operation is carried out.
Filtering Lists
Like projection, filtering a list is also a very common operation. To filter a list we apply a test to each item in the list and collect the items that pass into a new list.
exercise 6: Use forEach() to collect only those videos with a rating of 5.0
Use forEach() to loop through the videos in the newReleases list and, if a video has a rating of 5.0, add it to the videos list.
*/
public ComposableList<Video> exercise6() {
ComposableList<Video> newReleases = ComposableList.of(
new Video(
70111470,
"Die Hard",
4.0
),
new Video(
654356453,
"Bad Boys",
5.0
),
new Video(
65432445,
"The Chamber",
4.0
),
new Video(
675465,
"Fracture",
5.0
));
ComposableList<Video> highRatedVideos = new ComposableList<Video>();
// ------------ INSERT CODE HERE! -----------------------------------
// Use forEach function to accumulate every video with a rating of 5.0
// ------------ INSERT CODE HERE! -----------------------------------
// return highRatedVideos;
throw new UnsupportedOperationException("Not implemented yet.");
}
/*
Notice that like map() every filter() operation shares some operations in common:
1. Traverse the list
2. Add objects that pass the test to a new list
Why not create a helper function for this common pattern?
exercise 7: Implement filter()
If the List interface had a filter() method, it would make projections easier.
The filter method accepts a predicate test function to be applied to each
item in the source List. The filter method then returns a new List of all
of the items for which the predicate function returned true.
Ideally we'd be able to call ComposableList.of(1,2,3).filter(x -> x > 1) to
create a new List with a value of ComposableList.of(2,3). Unfortunately List
doesn't have a map method and there's no way for us to add one. However we
_can_ define a static method filter that accepts a list, a predicate
function and returns the filtered list.
filter(ComposableList.of(1,2,3), x -> x > 1) is equivalent to ComposableList.of(2,3)
*/
public ComposableList<T> filter(Predicate<T> predicateFunction) {
ComposableList<T> results = new ComposableList<T>();
for (T itemInList : this) {
// ------------ INSERT CODE HERE! ----------------------------
// Apply the predicateFunction to each item in the list. If the
// result is true, add the result to the results list.
// Note: you can apply the predicateFunction to a value like this:
// predicateFunction.test(5)
// ------------ INSERT CODE HERE! ----------------------------
// **************ANSWER START***************//
// if (predicateFunction.test(itemInList)) {
// results.add(itemInList);
// }
// **************ANSWER END***************//
}
// return results;
throw new UnsupportedOperationException("Not implemented yet.");
}
/*
Like map(), filter() let's us express what data we want without requiring us to specify how we want to collect the data.
Query Data by Chaining Method Calls
exercise 8: Chain filter and map to collect the ids of videos that have a rating of 5.0
*/
public ComposableList<Integer> exercise8() {
ComposableList<Video> newReleases
= ComposableList.of(
new Video(
70111470,
"Die Hard",
4.0
),
new Video(
654356453,
"Bad Boys",
5.0
),
new Video(
65432445,
"The Chamber",
4.0
),
new Video(
675465,
"Fracture",
5.0
));
// ------------ INSERT CODE HERE! -----------------------------------
// Chain the filter and map functions to select the id of all videos
// with a rating of 5.0.
//return newReleases // Complete this expression
// ------------ INSERT CODE HERE! -----------------------------------
throw new UnsupportedOperationException("Not implemented yet.");
}
/*
Chaining together map() and filter() gives us a lot of expressive power. These high level functions let us express what data we want, but leave the underlying libraries a great deal of flexibility in terms of how our queries are executed.
Querying Trees
Sometimes, in addition to flat lists, we need to query trees. Trees pose a challenge because we need to flatten them in order to apply filter() and map() operations on them. In this section we'll define a concatMap() function that we can use alongside or instead of map() to query trees.
exercise 9: Flatten the movieLists list into a list of video ids
Let's start by using two nested forEach loops collect the id of every video in the two-dimensional movieLists list.
*/
class MovieList {
public String name;
public ComposableList<Video> videos;
public MovieList(String name, ComposableList<Video> videos) {
this.name = name;
this.videos = videos;
}
}
public ComposableList<Integer> exercise9() {
ComposableList<MovieList> movieLists = ComposableList.of(
new MovieList(
"New Releases",
ComposableList.of(
new Video(70111470, "Die Hard", 4.0),
new Video(654356453, "Bad Boys", 5.0))),
new MovieList(
"Dramas",
ComposableList.of(
new Video(65432445, "The Chamber", 4.0),
new Video(675465, "Fracture", 5.0))));
ComposableList<Integer> allVideoIdsInMovieLists = new ComposableList<Integer>();
// ------------ INSERT CODE HERE! -----------------------------------
// Use two nested forEach loops to flatten the movieLists into a list of
// video ids.
// ------------ INSERT CODE HERE! -----------------------------------
//return allVideoIdsInMovieLists;
throw new UnsupportedOperationException("Not implemented yet.");
}
/*
Flattening trees with nested forEach expressions is easy because we can explicitly add items to the list. Unfortunately it's exactly this type of low-level operation that we've been trying to abstract away with functions like map() and filter(). Can we define a function that's abstract enough to express our intent to flatten a tree, without specifying too much information about how to carry out the operation?
exercise 10: Implement concatMap()
Flattening trees is very common. Ideally we'd be able to use a helper function to do the heavy lifting for us. Let's implement the concatMap() method for List. Like map(), the concatMap() function applies a projection function to each item in a list. However the projection function passed to concatMap converts each value into a List of values, creating a tree. Before returning the tree, the concatMap method flattens it. Here's an example of concatMap in action.
ComposableList.of(
ComposableList.of( 0, 1, 2),
ComposableList.of(10, 11, 12),
ComposableList.of(20, 21, 22))
.concatMap(x -> x * 10)
is equivalent to
ComposableList.of(0, 10, 20, 100, 110, 120, 200, 210, 220)
Unfortunately List doesn't have a concatMap method and there's no way for us to add one. However we _can_ define a static method concatMap. The concatMap method accepts a ComposableList<T> , a function that accepts a single value and returns a collection (Function<T, ComposableList<R>> ), and returns a flat list of the results (ComposableList<R> ).
*/
public <R> ComposableList<R> concatMap(Function<T, ComposableList<R>> projectionFunctionThatReturnsList) {
ComposableList<R> results = new ComposableList<R>();
for (T itemInList : this) {
// ------------ INSERT CODE HERE! ----------------------------
// Apply the projection function to each item in the list.
// This will create _another_ list. Then loop through each
// inner list and add each item to the flat results list.
// Note that you can apply a projectionFunction to a value like this:
// projectionFunctionThatReturnsList.apply(5)
// ------------ INSERT CODE HERE! ----------------------------
// **************ANSWER START***************//
// for(R itemInInnerList: projectionFunctionThatReturnsList.apply(itemInList)) {
// results.add(itemInInnerList);
// }
// **************ANSWER END***************//
}
return results;
}
/*
As you may have already guessed, the ComposableList class has the concatMap method. The concatMap method may seem pretty abstract at first, and it may not be immediately obvious how it can be used to transform data in a tree. In the next exercise we will combine this function with the map function to query a tree.
exercise 11: Use map() and concatMap() to project and flatten the movieLists into a stream of video ids
Hint: nest a map() call within a concatMap().
*/
public ComposableList<Integer> exercise11() {
ComposableList<MovieList> movieLists = ComposableList.of(
new MovieList(
"New Releases", // name
ComposableList.of( // videos
new Video(70111470, "Die Hard", 4.0),
new Video(654356453, "Bad Boys", 5.0))),
new MovieList(
"Dramas",
ComposableList.of(
new Video(65432445, "The Chamber", 4.0),
new Video(675465, "Fracture", 5.0))));
// ------------ INSERT CODE HERE! -----------------------------------
// Use map and concatAll to flatten the movieLists in a list of video ids.
// return movieLists // finish expression
// ------------ INSERT CODE HERE! -----------------------------------
// **************ANSWER START***************//
// return movieLists.
// concatMap(movieList ->
// movieList.videos.map(video -> video.id));
// **************ANSWER END***************//
throw new UnsupportedOperationException("Not implemented yet.");
}
/*
Wow! Great work. Mastering the combination of map() and concatMap() is key to effective functional programming. You're half way there! Let's try a more complicated example...
exercise 12: Retrieve id, title, and a 150x200 box art url for every video
You've managed to flatten a tree that's two levels deep, let's try for three! Let's say that instead of a single boxart url on each video, we had a collection of boxart objects, each with a different size and url. Create a query that selects {id, title, boxart} json for every video in the movieLists. This time though, the boxart property in the result will be the url of the boxart object with dimensions of 150x200px. Let's see if you can solve this problem using _only_ map(), concatMap(), and filter().
*/
class BoxArt {
public int width;
public int height;
public String url;
public BoxArt(int width, int height, String url) {
this.width = width;
this.height = height;
this.url = url;
}
}
public ComposableList<JSON> exercise12() {
ComposableList<MovieList> movieLists = ComposableList.of(
new MovieList(
"Instant Queue",
ComposableList.of(
new Video(
70111470,
"Die Hard",
5.0,
null,
ComposableList.of(
new BoxArt(150, 200, "http://cdn-0.nflximg.com/images/2891/DieHard150.jpg")
)),
new Video(
654356453,
"Bad Boys",
4.0,
null,
ComposableList.of(
new BoxArt(200, 200, "http://cdn-0.nflximg.com/images/2891/BadBoys200.jpg"),
new BoxArt(150, 200, "http://cdn-0.nflximg.com/images/2891/BadBoys150.jpg")
))
)
),
new MovieList(
"New Releases",
ComposableList.of(
new Video(
65432445,
"The Chamber",
4.0,
null,
ComposableList.of(
new BoxArt(150, 200, "http://cdn-0.nflximg.com/images/2891/TheChamber150.jpg")
)),
new Video(
675465,
"Fracture",
5.0,
null,
ComposableList.of(
new BoxArt(200, 200, "http://cdn-0.nflximg.com/images/2891/Fracture200.jpg"),
new BoxArt(150, 200, "http://cdn-0.nflximg.com/images/2891/Fracture150.jpg"),
new BoxArt(300, 200, "http://cdn-0.nflximg.com/images/2891/Fracture300.jpg")
))
)
)
);
// Use one or more map, concatAll, and filter calls to create an ComposableList with the following items
// {
// {"id": 675465,"title": "Fracture","boxart":"http://cdn-0.nflximg.com/images/2891/Fracture150.jpg" },
// {"id": 65432445,"title": "The Chamber","boxart":"http://cdn-0.nflximg.com/images/2891/TheChamber150.jpg" },
// {"id": 654356453,"title": "Bad Boys","boxart":"http://cdn-0.nflximg.com/images/2891/BadBoys150.jpg" },
// {"id": 70111470,"title": "Die Hard","boxart":"http://cdn-0.nflximg.com/images/2891/DieHard150.jpg" }
// };
// return movieLists // Complete this expression!
throw new UnsupportedOperationException("Not implemented yet.");
}
/*
It's a very common pattern to see several nested concatMap operations, with the last operation being a map. You can think of this pattern as the functional version of a nested forEach.
Reducing Lists
Sometimes we need to perform an operation on more than one item in the list at the same time. For example, let's say we need to find the largest integer in a list. We can't use a filter() operation, because it only examines one item at a time. To find the largest integer we need to the compare items in the list to each other.
One approach could be to select an item in the list as the assumed largest number (perhaps the first item), and then compare that value to every other item in the list. Each time we come across a number that was larger than our assumed largest number, we'd replace it with the larger value, and continue the process until the entire list was traversed.
If we replaced the specific size comparison with a lambda, we could write a function this handled the list traversal process for us. At each step our function would apply the lambda to the last value and the current value and use the result as the last value the next time. Finally we'd be left with only one value. This process is known as reducing because we reduce many values to a single value.
exercise 13: Use forEach to find the largest box art
In this example we use forEach to find the largest box art. Each time we examine a new boxart we update a variable with the currently known maximumSize. If the boxart is smaller than the maximum size, we discard it. If it's larger, we keep track of it. Finally we're left with a single boxart which must necessarily be the largest.
*/
public BoxArt exercise13() {
ComposableList<BoxArt> boxarts = ComposableList.of(
new BoxArt(200, 200, "http://cdn-0.nflximg.com/images/2891/Fracture200.jpg"),
new BoxArt(150, 200, "http://cdn-0.nflximg.com/images/2891/Fracture150.jpg"),
new BoxArt(300, 200, "http://cdn-0.nflximg.com/images/2891/Fracture300.jpg"),
new BoxArt(425, 150, "http://cdn-0.nflximg.com/images/2891/Fracture425.jpg")
);
int currentSize;
int maxSize = -1;
BoxArt largestBoxart = null;
for (BoxArt boxart : boxarts) {
currentSize = boxart.width * boxart.height;
if (currentSize > maxSize) {
largestBoxart = boxart;
maxSize = currentSize;
}
};
return largestBoxart;
}
/*
This process is a reduction because we're using the information we derived from the last computation to calculate the current value. However in the example above, we still have to specify the method of traversal. Wouldn't it be nice if we could just specify what operation we wanted to perform on the last and current value? Let's create a helper function to perform reductions on lists.
exercise 14: Implement reduce()
Let's add a reduce() function to the List type. Like map
*/
// [1,2,3].reduce(function(accumulatedValue, currentValue) { return accumulatedValue + currentValue; }); == [6];
// [1,2,3].reduce(function(accumulatedValue, currentValue) { return accumulatedValue + currentValue; }, 10); == [16];
public ComposableList<T> reduce(BiFunction<T, T, T> combiner) {
int counter = 1;
T accumulatedValue = null;
// If the list is empty, do nothing
if (this.size() == 0) {
return this;
} else {
accumulatedValue = this.get(0);
// Loop through the list, feeding the current value and the result of
// the previous computation back into the combiner function until
// we've exhausted the entire list and are left with only one function.
while (counter < this.size()) {
accumulatedValue = combiner.apply(accumulatedValue, this.get(counter));
counter++;
}
return ComposableList.of(accumulatedValue);
}
}
;
public <R> ComposableList<R> reduce(R initialValue, BiFunction<R, T, R> combiner) {
int counter;
R accumulatedValue;
// If the list is empty, do nothing
if (this.size() == 0) {
return new ComposableList<R>();
} else {
counter = 0;
accumulatedValue = initialValue;
// Loop through the list, feeding the current value and the result of
// the previous computation back into the combiner function until
// we've exhausted the entire list and are left with only one function.
while (counter < this.size()) {
accumulatedValue = combiner.apply(accumulatedValue, this.get(counter));
counter++;
}
return ComposableList.of(accumulatedValue);
}
}
;
/*
exercise 16: Retrieve the largest rating.
Let's use our new reduce function to isolate the largest value in a list of ratings.
*/
public ComposableList<Integer> exercise16() {
ComposableList<Integer> ratings = ComposableList.of(2, 3, 1, 4, 5);
// You should return a list containing only the largest rating. Remember that reduce always
// returns a list with one item.
// complete the expression below
//return ratings.reduce
throw new UnsupportedOperationException("Not implemented yet.");
}
/*
Nice work. Now let's try combining reduce() with our other functions to build more complex queries.
exercise 17: Retrieve url of the largest boxart
Let's try combining reduce() with map() to reduce multiple boxart objects to a single value: the url of the largest box art.
*/
public ComposableList<String> exercise17() {
ComposableList<BoxArt> boxarts = ComposableList.of(
new BoxArt(200, 200, "http://cdn-0.nflximg.com/images/2891/Fracture200.jpg"),
new BoxArt(150, 200, "http://cdn-0.nflximg.com/images/2891/Fracture150.jpg"),
new BoxArt(300, 200, "http://cdn-0.nflximg.com/images/2891/Fracture300.jpg"),
new BoxArt(425, 150, "http://cdn-0.nflximg.com/images/2891/Fracture425.jpg")
);
// You should return a list containing only the largest box art. Remember that reduce always
// returns a list with one item.
// return boxarts.reduce
throw new UnsupportedOperationException("Not implemented yet.");
}
/*
exercise 18: Reducing with an initial value
Sometimes when we reduce a list, we want the reduced value to be a different type than the items stored in the list. Let's say we have a list of videos and we want to reduce them to a single map where the key is the video id and the value is the video's title.
*/
public ComposableList<Map<Integer, String>> exercise18() {
ComposableList<Video> videos = ComposableList.of(
new Video(
65432445,
"The Chamber",
5.0
),
new Video(
675465,
"Fracture",
4.0
),
new Video(
70111470,
"Die Hard",
5.0
),
new Video(
654356453,
"Bad Boys",
3.0
)
);
// Expecting this output...
// [
// {
// "65432445": "The Chamber",
// "675465": "Fracture",
// "70111470": "Die Hard",
// "654356453": "Bad Boys"
// }
// ]
/*
return videos.
reduce(
// Use an empty map as the initial value instead of the first item in
// the list.
new HashMap<Integer, String> (),
(accumulatedMap, video) -> {
return copyOfAccumulatedMap;
});
*/
throw new UnsupportedOperationException("Not implemented yet.");
}
/*
Nice work. Now let's try combining reduce() with our other functions to build more complex queries.
exercise 19: Retrieve the id, title, and smallest box art url for every video.
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.
*/
public ComposableList<JSON> exercise19() {
ComposableList<MovieList> movieLists = ComposableList.of(
new MovieList(
"New Releases",
ComposableList.of(
new Video(
70111470,
"Die Hard",
4.0,
null,
ComposableList.of(
new BoxArt(150, 200, "http://cdn-0.nflximg.com/images/2891/DieHard150.jpg"),
new BoxArt(200, 200, "http://cdn-0.nflximg.com/images/2891/DieHard200.jpg")
)),
new Video(
654356453,
"Bad Boys",
5.0,
null,
ComposableList.of(
new BoxArt(200, 200, "http://cdn-0.nflximg.com/images/2891/BadBoys200.jpg"),
new BoxArt(140, 200, "http://cdn-0.nflximg.com/images/2891/BadBoys140.jpg")
))
)
),
new MovieList(
"Thrillers",
ComposableList.of(
new Video(
65432445,
"The Chamber",
3.0,
null,
ComposableList.of(
new BoxArt(130, 200, "http://cdn-0.nflximg.com/images/2891/TheChamber130.jpg"),
new BoxArt(200, 200, "http://cdn-0.nflximg.com/images/2891/TheChamber200.jpg")
)),
new Video(
675465,
"Fracture",
4.0,
null,
ComposableList.of(
new BoxArt(200, 200, "http://cdn-0.nflximg.com/images/2891/Fracture200.jpg"),
new BoxArt(120, 200, "http://cdn-0.nflximg.com/images/2891/Fracture120.jpg"),
new BoxArt(300, 200, "http://cdn-0.nflximg.com/images/2891/Fracture300.jpg")
))
)
)
);
// Use one or more concatMap, map, and reduce calls to create a list with the following items (order doesn't matter)
// [
// {"id": 675465,"title": "Fracture","boxart":"http://cdn-0.nflximg.com/images/2891/Fracture120.jpg" },
// {"id": 65432445,"title": "The Chamber","boxart":"http://cdn-0.nflximg.com/images/2891/TheChamber130.jpg" },
// {"id": 654356453,"title": "Bad Boys","boxart":"http://cdn-0.nflximg.com/images/2891/BadBoys140.jpg" },
// {"id": 70111470,"title": "Die Hard","boxart":"http://cdn-0.nflximg.com/images/2891/DieHard150.jpg" }
// ];
/*
return movieLists.
concatMap(function(movieList) {
})
*/
throw new UnsupportedOperationException("Not implemented yet.");
}
/*
Zipping Lists
Sometimes we need to combine two lists by progressively taking an item from each and combining the pair. If you visualize a zipper, where each side is a list, and each tooth is an item, you'll have a good idea of how the zip operation works.
exercise 20: Combine videos and bookmarks by index
Use a for loop to traverse the videos and bookmarks list at the same time. For each video and bookmark pair, create a {videoId, bookmarkId} pair and add it to the videoIdAndBookmarkIdPairs list.
*/
public ComposableList<JSON> exercise20() {
ComposableList<Video> videos = ComposableList.of(
new Video(
70111470,
"Die Hard",
4.0
),
new Video(
654356453,
"Bad Boys",
5.0
),
new Video(
65432445,
"The Chamber",
4.0
),
new Video(
675465,
"Fracture",
5.0
)
);
ComposableList<Bookmark> bookmarks = ComposableList.of(
new Bookmark(470, 23432),
new Bookmark(453, 234324),
new Bookmark(445, 987834)
);
ComposableList<JSON> videoIdAndBookmarkIdPairs = new ComposableList<JSON>();
for (int counter = 0; counter < Math.min(videos.size(), bookmarks.size()); counter++) {
// Insert code here to create a {videoId, bookmarkId} pair and add it to the videoIdAndBookmarkIdPairs list.
}
// return videoIdAndBookmarkIdPairs;
throw new UnsupportedOperationException("Not implemented yet.");
}
/*
exercise 21: Implement zip
Let's add a static zip() function to the List type. The zip function accepts a combiner function, traverses each list at the same time, and calls the combiner function on the current item on the left-hand-side and right-hand-side. The zip function requires an item from each list in order to call the combiner function, therefore the list returned by zip will only be as large as the smallest input list.
*/
// JSON.stringify(List.zip([1,2,3],[4,5,6], function(left, right) { return left + right })) == '[5,7,9]' accumulatedValue + currentValue; }); == [6];
public static <T0,T1,R> ComposableList<R> zip(ComposableList<T0> left, ComposableList<T1> right, BiFunction<T0,T1, R> combinerFunction) {
ComposableList<R> results = new ComposableList<R>();
for (int counter = 0; counter < Math.min(left.size(), right.size()); counter++) {
// Add code here to apply the combinerFunction to the left and right-hand items in the respective lists
}
// return results;
throw new UnsupportedOperationException("Not implemented yet.");
}
;
/*
exercise 22: Combine videos and bookmarks by index
Let's repeat exercise 20, but this time let's use your new zip() function. For each video and bookmark pair, create a {videoId, bookmarkId} pair.
*/
public ComposableList<JSON> exercise22() {
ComposableList<Video> videos = ComposableList.of(
new Video(
70111470,
"Die Hard",
4.0
),
new Video(
654356453,
"Bad Boys",
5.0
),
new Video(
65432445,
"The Chamber",
4.0
),
new Video(
675465,
"Fracture",
5.0
)
);
ComposableList<Bookmark> bookmarks = ComposableList.of(
new Bookmark(470, 23432),
new Bookmark(453, 234324),
new Bookmark(445, 987834)
);
// return ComposableList.zip( //... finish this expression
throw new UnsupportedOperationException("Not implemented yet.");
}
/*
exercise 23: Retrieve each video's id, title, middle interesting moment time, and smallest box art url.
This is a variation of the problem we solved earlier. This time each video has an interesting moments collection, each representing a time during which a screenshot is interesting or representative of the title as a whole. Notice that both the boxarts and interestingMoments lists are located at the same depth in the tree. Retrieve the time of the middle interesting moment and the smallest box art url simultaneously with zip(). Return an {id, title, time, url} object for each video.
*/
ComposableList<JSON> exercise23() {
ComposableList<MovieList> movieLists = ComposableList.of(
new MovieList(
"New Releases",
ComposableList.of(
new Video(
70111470,
"Die Hard",
4.0,
null,
ComposableList.of(
new BoxArt(150, 200, "http://cdn-0.nflximg.com/images/2891/DieHard150.jpg"),
new BoxArt(200, 200, "http://cdn-0.nflximg.com/images/2891/DieHard200.jpg")
),
ComposableList.of(
new InterestingMoment("End", 213432),
new InterestingMoment("Start", 64534),
new InterestingMoment("Middle", 323133)
)
),
new Video(
654356453,
"Bad Boys",
5.0,
null,
ComposableList.of(
new BoxArt(200, 200, "http://cdn-0.nflximg.com/images/2891/BadBoys200.jpg"),
new BoxArt(140, 200, "http://cdn-0.nflximg.com/images/2891/BadBoys140.jpg")
),
ComposableList.of(
new InterestingMoment("End", 54654754),
new InterestingMoment("Middle", 6575665)
)
)
)
),
new MovieList(
"Instant Queue",
ComposableList.of(
new Video(
65432445,
"The Chamber",
4.0,
null,
ComposableList.of(
new BoxArt(130, 200, "http://cdn-0.nflximg.com/images/2891/TheChamber130.jpg"),
new BoxArt(200, 200, "http://cdn-0.nflximg.com/images/2891/TheChamber200.jpg")
),
ComposableList.of(
new InterestingMoment("End", 132423),
new InterestingMoment("Start", 54637425),
new InterestingMoment("Middle", 3452343)
)
),
new Video(
675465,
"Fracture",
5.0,
null,
ComposableList.of(
new BoxArt(200, 200, "http://cdn-0.nflximg.com/images/2891/Fracture200.jpg"),
new BoxArt(120, 200, "http://cdn-0.nflximg.com/images/2891/Fracture120.jpg"),
new BoxArt(300, 200, "http://cdn-0.nflximg.com/images/2891/Fracture300.jpg")
),
ComposableList.of(
new InterestingMoment("End", 45632456),
new InterestingMoment("Start", 234534),