Skip to content

Instantly share code, notes, and snippets.

@Solonarv
Last active December 21, 2015 18:38
Show Gist options
  • Save Solonarv/08aa7bd7f69d0e95d15e to your computer and use it in GitHub Desktop.
Save Solonarv/08aa7bd7f69d0e95d15e to your computer and use it in GitHub Desktop.
A linked-list reimplementation in Java 8, with a functional interface.
@FunctionalInterface
public interface BinOp<T, U, V> {
abstract V op(T x, U y);
}
@FunctionalInterface
public interface Function<T, U> {
abstract U run(T x);
}
/**
* A nice, generic linked list implementation.
*
* @author Solonarv
*
* @param <T>
* the type of the list's elements.
*/
public class LinkedList<T> {
protected ConsCell<T> head;
// Cached for efficiency
protected ConsCell<T> last;
protected int length;
public LinkedList() {
this.head = null;
this.last = null;
}
public void add(T elem) {
ConsCell<T> newLast = new ConsCell<>(elem);
if (this.last != null) {
this.last.cdr = newLast;
}
this.last = newLast;
this.length++;
}
public void add(T elem, int index) {
if (index < 0 || index >= this.length - 1) {
this.add(elem);
return;
}
ConsCell<T> prev = null;
ConsCell<T> current = this.head;
for (int i = 0; i < index; i++) {
prev = current;
current = current.cdr;
}
ConsCell<T> newCell = new ConsCell<>(elem, current);
prev.cdr = newCell;
this.length++;
}
public boolean remove(int index) {
if (index < 0 || index >= this.length) {
return false;
}
ConsCell<T> prev = null;
ConsCell<T> current = this.head;
for (int i = 0; i < index; i++) {
prev = current;
current = current.cdr;
}
prev.cdr = current.cdr;
this.length--;
return true;
}
public T getFirst() {
if (this.head == null) {
return null;
}
return this.head.car;
}
public T getLast() {
if (this.last == null) {
return null;
}
return this.last.car;
}
public T get(int index) {
if (index < 0 || index >= this.length) {
return null;
}
ConsCell<T> current = this.head;
for (int i = 0; i < index; i++) {
current = current.cdr;
}
return current.car;
}
public boolean remove(T elem) {
if (this.head == null) {
return false;
}
ConsCell<T> prev = null;
ConsCell<T> current = this.head;
boolean found = false;
while (current != null) {
if (current.car.equals(elem)) {
found = true;
break;
}
prev = current;
current = current.cdr;
}
if (found) {
prev.cdr = current.cdr;
this.length--;
return true;
}
return false;
}
// Alternate implementation: return this.find(other) != null;
// This is probably more efficient though.
public boolean contains(T other) {
return this.foldr(false, (Boolean acc, T elem) -> {
return acc || elem.equals(other);
});
}
public T find(T other) {
return this.foldr(null, (BinOp<T, T, T>) ((T acc, T elem) -> {
return (acc != null) ? acc : (elem.equals(other) ? elem : null);
}));
}
protected <R> R foldr(R startingAcc, BinOp<R, T, R> f) {
R acc = startingAcc;
ConsCell<T> current = this.head;
while (current != null) {
acc = f.op(acc, current.car);
current = current.cdr;
}
return acc;
}
public int size() {
return this.length;
}
public <U> LinkedList<U> map(Function<T, U> f) {
return this.foldr(new LinkedList<U>(), (BinOp<LinkedList<U>, T, LinkedList<U>>) (LinkedList<U> acc, T elem) -> {
return acc.cons(f.run(elem));
});
}
public LinkedList<T> cons(T elem) {
this.head = new ConsCell<>(elem, this.head);
return this;
}
protected class ConsCell<V> {
public V car;
public ConsCell<V> cdr;
public ConsCell(V car, ConsCell<V> cdr) {
this.car = car;
this.cdr = cdr;
}
public ConsCell(V car) {
this(car, null);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment