course-web-page-Fall-2021

Repository for the Fall 2021 course web page

View the Project on GitHub IUDataStructuresCourse/course-web-page-Fall-2021

Lecture: Linked lists and Streams

“The Tao gave birth to machine language. Machine language gave birth to the assembler. The assembler gave birth to the compiler. Now there are ten thousand languages. Each language has its purpose, however humble. Each language expresses the Yin and Yang of software. Each language has its place within the Tao. But do not program in COBOL if you can avoid it.”

–The Tao of Programming

Example sum of squares on linked list

int sum_of_squares_list(Node begin) {
    int total = 0;
    for (Node n = begin; n != null; n = n.next) {
       total += n.data * n.data;
    }
    return total;
}

Example sum of squares on array

int sum_of_squares_array(int[] array) {
    int total = 0;
    for (int n = begin; n != array.length; ++n) {
       total += n.data * n.data;
    }
    return total;
}

Linked lists and arrays can both be accessed through the Stream interface. Java interfaces are a Java-specific way to express Abstract Data Types.

Here’s how to implement sum of squares on a Stream.

int sum_of_squares_stream(Stream<Integer> s) {
    return s.map(x -> x * x).reduce(0, (x,y) -> x + y);
}

Map: apply a function f to every element of the stream

[a, b, c, d]
=>
[f(a), f(b), f(c), f(d)]

Reduce: combine all the elements of the stream using a function g, starting at an initial value init.

[a, b, c, d]
=>
g(a, g(b, g(c, g(d, init))))

If the stream is empty, the result of reduce is init.

[]
=>
init

We can then implement the list and array functions using the stream version.

int sum_of_squares_list(LinkedList<Integer> xs) {
    return sum_of_squares_stream(xs.stream());
}

int sum_of_squares_array(ArrayList<Integer> xs) {
    return sum_of_squares_stream(xs.stream());
}

Looking under the hood, map could be implemented as follows in terms of the Stream operations concat, of, empty, and an extra function of my own devising called match that returns the first element of the stream and the rest of the stream, provided the stream is not empty.

static <T,R> Stream<R> mymap(Stream<T> s, Function<T,R> f) {
   Optional<Pair<T,Stream<T>>> opt = match(s);
   if (opt.isPresent()) {
	  T elt = opt.get().fst;
	  Stream<T> rest = opt.get().snd;
	  return Stream.concat(Stream.of(f.apply(elt)), mymap(rest, f));
   } else {
	  return Stream.empty();
   }
}