---
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