Rec 07

Problems

01. Infinite List

  1. When returning/creating a new Infinite List, always think about how to come up with the head and the tail!

  2. Know how to pass in a curried lambda when the transformer will transform a value into another transformer

As for point 1, look at the question a) and b) will be quite enough. For point 2, let's see the follwing example, which is question b)

public <S, R> InfiniteList<R> zipWith(
  InfiniteList<? extends S> list,
  Transformer<? super T, ? extends Transformer<? super S, ? extends R>> mapper) {
}

This method zipWith 's second parameter is a transformer that transforms a value into another transformer. As such, when we pass a lambda in, we should pass a curriend lambda. For example,

jshell> InfiniteList<Integer> l1 = InfiniteList.iterate(0, i -> i + 1);;
jshell> InfiniteList<String> l2 = InfiniteList.iterate("", s -> s + "S");;
jshell> InfiniteList<Object> l3 = l1.zipWith(l2, i -> s -> i + s.length());

In the curried lambda, the i at the end is actually accessed via variable capture. To visualize it vividly, we can rewrite the curried lambda into the anonymous class

new Transformer<Integer, Transformer<String, Integer>>() {
    @Override
    public Transformer<String, Integer> transform(Integer i) {
        return new Transformer<String, Integer>() {
            @Override
            public Integer transform(String s) {
                return i + s.length(); // <-- i is captured here!
            }
        };
    }
}

Now, we can use our head and tail thinking to implement the zipWith method

A small trick is to look at the given sample code to decide when to use this.head()/tail() and when to use list.head()/tail().

02. Stream Construction

  1. iterate() is general enough so that we can use it to build a Stream whose elements is Pair! Include the example in the cheatsheet!

  2. map() and flatMap() have different use cases

    1. map() is usually used when each element in the previous Stream has a one-to-one relationship with the elements in the new Stream.

    2. flatMap() is usally used when each element in the previous Stream has a one-to-multiple relationship with the elements in the new Stream.

For example, to create a Fibonacci Stream, we can use the following code

03. Stream Construction*

This question is awesome and it is worth to try again before Final/PE2! It vividly shows the difference between flatMap() and map()

Write a method product that takes in two List objects list1 and list2 , and produce a Stream containing elements combining each element from list1 with evey element from list2 using a given lambda expression of type BiFunction .

The sample jshell code is given below:


To do this kind of questions, determine our steps first!

  1. Get the element of list1

  2. Get the element of list2

  3. Pass them to the BiFunction func.

After that, we have a brief idea that we may use map()/flatMap() to retrieve the elements. How to make sure which one to use? Let's look at the sample code,

  1. After we retrieve the first element of list1, which is 1. For each element of list2, we use 1 and it to form two new elements in our new Stream. This is actually a one-to-multiple relationship! So, flatMap() should be used to retrieve the elements from list1

  2. Then after retrieve element from list2, we find that it is a one-to-one relationship! So, map() should be used!

In the end, we have the final answer!

04. Stream Construction*

  1. Include the Stream implementation of isPrime()/ countPrimeFactors() into cheatsheet!

Follow the systematetic steps, to solve the questions

  1. Generate a continious stream

  2. Map each value to its number of Prime Factors

Knowing this, our final solution will be

Tips

  1. When returning/creating a new Infinite List, always think about how to come up with the head and the tail!

  2. Know how to pass in a curried lambda when the transformer will transform a value into another transformer

  3. iterate() is general enough so that we can use it to build a Stream whose elements is Pair! Include the example in the cheatsheet!

  4. map() and flatMap() have different use cases

    1. map() is usually used when each element in the previous Stream has a one-to-one relationship with the elements in the new Stream.

    2. flatMap() is usally used when each element in the previous Stream has a one-to-multiple relationship with the elements in the new Stream.

  5. In Stream Construction problems, always be clear about what are your steps to solve the problem!

Last updated