---
# System prepended metadata

title: Comparators and Function Notes
tags: [fall 2018 cs61b]

---

---
tags: fall 2018 cs61b
---
# Comparators and Function Notes
[TOC]
## Comparables and Comparators
Suppose we're given an array or list of objects. We want to be able to sort the objects in the list/array based on some order (e.g. descendingOrder, ascendingOrder, etc). This is where `Comparable` and `Comparator` come in!

### What is the difference between a Comparable object and Comparator object?

**Comparable**
A `Comparable` object is able to compared with itself by some metric. It also *implements* the `Comparable` interface. 

**Comparable interface:**
```Java
interface Comparable<T> {

    //compares the current object calling this method to the object in the parameter 
    int compareTo(T o);
}
```
`compareTo` returns an `int` value based on if `o` should be before or after the current object calling the method. 

If `o` is "larger" than the current object and should be sorted behind it, then `compareTo` returns a negative number. 

If `o` is "smaller" than the current object and should be sorted before it, then `compareTo` returns a positive number. 

If `o` is "equal" to the current object, then `compareTo` returns 0.

**Common Usage of compareTo:**
```Java
//String implements Comparable and has a compareTo method
//allows you to compare different Strings lexographically
String longWord = "longlonglonglongword";
String shortWord = "shortword";
String equalWord = "shortword";

longword.compareTo(shortWord); //returns negative integer
shortword.compareTo(longWord); //returns positive integer
equalword.compareTo(shortWord); //returns 0
```

**Comparator**
A `Comparator` determines the metric for comparison.

**Comparator interface:**
```Java
class Comparator<T> {

    //Compares its two arguments of type T for order. 
    compare(T o1, T o2);
    
}
```
The method `compare` returns a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second. If `o1<o2`, then `compare` returns a negative number. If `o1>o2`, then `compare` returns a positive number. If `o1=o2`, then `compare` returns 0.

#### Common Usage
```Java
String[] arr = new String[]{"hi","whatever","fun"};

//Arrays.sort is used for arrays
Arrays.sort(arr, /* Comparator object that compares objects in arr*/);

ArrayList<String> a = new ArrayList<>();
a.add("hi")
a.add("whatever")
a.add("fun")

//Collections.sort is used for Lists
Collections.sort(a, /* Comparator object that compares objects in a*/);
```

Now, let's actually create a `Comparator` object.

Suppose we want to sort the Strings in the array below by their length (longest will be last). We can create a `Comparator` object that will do this for us. Note: Before making a comparator, make sure objects being compared in the `compare` method are comparable!

Note: It's common convention for `Comparator` classes to be implemented directly when we try to create an `Comparator` instance object.
```Java
String[] arr = new String[]{"hi", "whatever", "fun"};

Comparator<String> arrComp= new Comparator<String>() {
    //what is this doing? We're directly creating a StringComparator class
    // new Comparator<String> is then instantiating an instance object of this class
    @Override 
    public int compare(String o1, String o2) {
        //short complicated version
        //return (new Integer(o1.length())).compareTo(new Integer(o2.length()));
        
        //longer clearer version
        if (o1.length == o2.length) {
            return 0;
        } else if (o1.length < o2.length) {
            return -1;
        } else {
            return 1;
        }
    }
};

Arrays.sort(arr, arrComp);

//arr should now look like ['hi', 'fun', 'whatever']
System.println(a[0]); //prints hi
System.println(a[1]); //prints fun
System.println(a[2]); //prints whatever
```

### Strange Syntax
The most confusing part about comparators is the syntax. As shown above, we can instantly create an object `Comparator` class and instantiate it in a couple of lines. We can also create `Comparator` instance objects in a couple of other ways.

Suppose, we're still trying to create a `Comparator` object that sorts Strings based on their length.
```Java
Comparator<String> arrComp = (s1, s2) -> (new Integer(s1.length())).compareTo(new Integer(s2.length()));
```
The code above is using a *lambda expression* to express the `compare(String o1, String o2)` method. In this case, `s1` and `s2` are the two String objects being compared. The `->` operator divides the expression, so the left side refers to the parameters and the right side  specifies the actions of the expression.

We can also use a function and a `Function` object to create a `Comparator` object.

**Comparators Using Function**
Now, let's write our function that uses a `Function` object to return a `Comparator`. If you're confused, review the Function section below!

```Java
public static Comparator<String> getStringComp(Function<String, Integer> getter){
    return (s1, s2) -> getter.apply(s1).compareTo(getter.apply(s2))
}

//We can call the function the following way:
Function<String, Integer> getter = String::length;
Comparator<String> arrComp = getStringComp(getter);
```


## Function Object

Since Java cannot pass functions as parameters, it will pass in a `Function` object instead. There is a Java interface called [`Function`](https://docs.oracle.com/javase/8/docs/api/java/util/function/Function.html#apply-T-) that allows you create `Function` objects. 

```Java
interface Function<T,R> {
    //takes in an input of type T and returns a Type R
    R apply(T t);
}
```
`T` is meant to be the type of your input that your function can be applied to and **R** is the type that is outputted.

We want to write a `Function` object that takes in a String and returns its length so we can use it in our comparator!

### What does the `Apply` method do?
The `apply` method is meant to apply the specified function to an object or take in a parameter to input into the function. More specified below:

1. You can input an object that you want to call the function on (e.g. if you pass in a `User` object called `u1` and the `Function` is `User::getEmail`, then `apply(u1)` is really calling `u1.getEmail()`).

2. You can input an object that you want to pass into the function as an input (i.e. if the `Function` is referring to a method that takes in a parameter, then you can input the parameter into apply to pass it into the method).

### Instantiating a Function Object
`Function` is a special type of interface called a [functional interface](https://docs.oracle.com/javase/8/docs/api/java/lang/FunctionalInterface.html), which means instances of the interface can be created with lambda expressions, method references, or constructor references.
```Java
//First Way: Constructor Reference
Function<String, Integer> getter = new Function<String, Integer>() {
    Integer apply(String s) {
        return s.length();
    }
};

//Second Way: Method Reference
Function<String, Integer> getter = String::length;
// '::' operator divides the expression
// the left hand side refers to the class that contains the method
// the right hand side refers to the method name

//Third Way: Lambda Expression
Function<String, Integer> getter = (s) -> s.length;
```

### Primitive Function Specialization
If we take a look at the `Function` spec, we realize that `Function` is limited to taking in objects as parameters. What if we want to insert a primitive type such as an int?

Well, one way is to instantiate the int as an `Integer` through:
```
Integer i = new Integer(5);
```

However, we can also use other `Function` interfaces from the [java.util.function](https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html) package! There are three types of these objects:
* `IntFunction`, `LongFunction`, `DoubleFunction`: arguments are of specified type and return type is an object
* `ToIntFunction`, `ToLongFunction`, `ToDoubleFunction`: return type is of specified type, arguments are objects
* `DoubleToIntFunction`, `DoubleToLongFunction`, `IntToDoubleFunction`, `IntToLongFunction`, `LongToIntFunction`, `LongToDoubleFunction`: having both argument and return type defined as primitive types, as specified by their names