
fj.data.NonEmptyList Maven / Gradle / Ivy
package fj.data;
import fj.*;
import fj.function.Effect1;
import java.util.Collection;
import java.util.Iterator;
import static fj.Function.flip;
import static fj.Function.identity;
import static fj.Function.uncurryF2;
import static fj.data.Option.some;
import static fj.data.Option.somes;
/**
* Provides an in-memory, immutable, singly linked list with total head
and tail
.
*
* @version %build.number%
*/
public final class NonEmptyList implements Iterable {
/**
* Returns an iterator for this non-empty list. This method exists to permit the use in a for
-each loop.
*
* @return A iterator for this non-empty list.
*/
public Iterator iterator() {
return toCollection().iterator();
}
private final A head;
private final List tail;
/**
* The first element of this linked list.
*/
public A head() { return head; }
/**
* This list without the first element.
*/
public List tail() { return tail; }
private NonEmptyList(final A head, final List tail) {
this.head = head;
this.tail = tail;
}
/**
* Prepend the given value to this list.
*
* @param a The value to prepend.
* @return A non-empty list with an extra element.
*/
public NonEmptyList cons(final A a) {
return nel(a, tail.cons(head));
}
/**
* Appends (snoc) the given element to this non empty list to produce a new non empty list. O(n).
*
* @param a The element to append to this non empty list.
* @return A new non empty list with the given element appended.
*/
public NonEmptyList snoc(final A a) {
return nel(head, tail.snoc(a));
}
/**
* The length of this list.
*
* @return The length of this list.
*/
public int length() { return 1 + tail.length(); }
/**
* Appends the given list to this list.
*
* @param as The list to append.
* @return A new list with the given list appended.
*/
public NonEmptyList append(final List as) {
return nel(head, tail.append(as));
}
/**
* Appends the given list to this list.
*
* @param as The list to append.
* @return A new list with the given list appended.
*/
public NonEmptyList append(final NonEmptyList as) {
final List.Buffer b = new List.Buffer<>();
b.append(tail);
b.snoc(as.head);
b.append(as.tail);
final List bb = b.toList();
return nel(head, bb);
}
/**
* Performs a right-fold reduction across this list. This function uses O(length) stack space.
*/
public final A foldRight1(final F> f) {
return reverse().foldLeft1(flip(f));
}
/**
* Performs a right-fold reduction across this list. This function uses O(length) stack space.
*/
public final A foldRight1(final F2 f) {
return reverse().foldLeft1(flip(f));
}
/**
* Performs a left-fold reduction across this list. This function runs in constant space.
*/
public final A foldLeft1(final F> f) {
return foldLeft1(uncurryF2(f));
}
/**
* Performs a left-fold reduction across this list. This function runs in constant space.
*/
public final A foldLeft1(final F2 f) {
A x = head;
for (List xs = tail; !xs.isEmpty(); xs = xs.tail()) {
x = f.f(x, xs.head());
}
return x;
}
/**
* Maps the given function across this list.
*
* @param f The function to map across this list.
* @return A new list after the given function has been applied to each element.
*/
public NonEmptyList map(final F f) {
return nel(f.f(head), tail.map(f));
}
/**
* Binds the given function across each element of this list with a final join.
*
* @param f The function to apply to each element of this list.
* @return A new list after performing the map, then final join.
*/
public NonEmptyList bind(final F> f) {
final List.Buffer b = new List.Buffer<>();
final NonEmptyList p = f.f(head);
b.snoc(p.head);
b.append(p.tail);
tail.foreachDoEffect(a -> {
final NonEmptyList p1 = f.f(a);
b.snoc(p1.head);
b.append(p1.tail);
});
final List bb = b.toList();
return nel(bb.head(), bb.tail());
}
/**
* Returns a NonEmptyList of the sublists of this list.
*
* @return a NonEmptyList of the sublists of this list.
*/
public NonEmptyList> sublists() {
return fromList(
somes(toList().toStream().substreams()
.map(F1Functions.o(NonEmptyList::fromList, Conversions.Stream_List())).toList())).some();
}
/**
* Returns a NonEmptyList of the tails of this list. A list is considered a tail of itself for the purpose of this
* function (Comonad pattern).
*
* @return A NonEmptyList of the tails of this list.
*/
public NonEmptyList> tails() {
return fromList(somes(toList().tails().map(NonEmptyList::fromList))).some();
}
/**
* Maps the given function across the tails of this list (comonad pattern).
*
* @param f The function to map across the tails of this list.
* @return The results of applying the given function to the tails of this list, as a NonEmptyList.
*/
public NonEmptyList mapTails(final F, B> f) {
return tails().map(f);
}
/**
* Intersperses the given argument between each element of this non empty list.
*
* @param a The separator to intersperse in this non empty list.
* @return A non empty list with the given separator interspersed.
*/
public NonEmptyList intersperse(final A a) {
final List list = toList().intersperse(a);
return nel(list.head(), list.tail());
}
/**
* Reverse this non empty list in constant stack space.
*
* @return A new non empty list with the elements in reverse order.
*/
public NonEmptyList reverse() {
final List list = toList().reverse();
return nel(list.head(), list.tail());
}
/**
* Sorts this non empty list using the given order over elements using a merge sort algorithm.
*
* @param o The order over the elements of this non empty list.
* @return A sorted non empty list according to the given order.
*/
public NonEmptyList sort(final Ord o) {
final List list = toList().sort(o);
return nel(list.head(), list.tail());
}
/**
* Returns the minimum element in this non empty list according to the given ordering.
*
* @param o An ordering for the elements of this non empty list.
* @return The minimum element in this list according to the given ordering.
*/
public final A minimum(final Ord o) {
return foldLeft1(o::min);
}
/**
* Returns the maximum element in this non empty list according to the given ordering.
*
* @param o An ordering for the elements of this non empty list.
* @return The maximum element in this list according to the given ordering.
*/
public final A maximum(final Ord o) {
return foldLeft1(o::max);
}
/**
* Zips this non empty list with the given non empty list to produce a list of pairs. If this list and the given list
* have different lengths, then the longer list is normalised so this function never fails.
*
* @param bs The non empty list to zip this non empty list with.
* @return A new non empty list with a length the same as the shortest of this list and the given list.
*/
public NonEmptyList> zip(final NonEmptyList bs) {
final List> list = toList().zip(bs.toList());
return nel(list.head(), list.tail());
}
/**
* Zips this non empty list with the index of its element as a pair.
*
* @return A new non empty list with the same length as this list.
*/
public NonEmptyList> zipIndex() {
final List> list = toList().zipIndex();
return nel(list.head(), list.tail());
}
/**
* Zips this non empty list with the given non empty list using the given function to produce a new list. If this list
* and the given list have different lengths, then the longer list is normalised so this function
* never fails.
*
* @param bs The non empty list to zip this non empty list with.
* @param f The function to zip this non empty list and the given non empty list with.
* @return A new non empty list with a length the same as the shortest of this list and the given list.
*/
public NonEmptyList zipWith(final List bs, final F> f) {
final List list = toList().zipWith(bs, f);
return nel(list.head(), list.tail());
}
/**
* Zips this non empty list with the given non empty list using the given function to produce a new list. If this list
* and the given list have different lengths, then the longer list is normalised so this function
* never fails.
*
* @param bs The non empty list to zip this non empty list with.
* @param f The function to zip this non empty list and the given non empty list with.
* @return A new non empty list with a length the same as the shortest of this list and the given list.
*/
public NonEmptyList zipWith(final List bs, final F2 f) {
final List list = toList().zipWith(bs, f);
return nel(list.head(), list.tail());
}
/**
* Transforms a non empty list of pairs into a non empty list of first components and
* a non empty list of second components.
*
* @param xs The non empty list of pairs to transform.
* @return A non empty list of first components and a non empty list of second components.
*/
public static P2, NonEmptyList> unzip(final NonEmptyList> xs) {
final P2, List> p = List.unzip(xs.toList());
return P.p(nel(p._1().head(), p._1().tail()), nel(p._2().head(), p._2().tail()));
}
/**
* Returns a List
projection of this list.
*
* @return A List
projection of this list.
*/
public List toList() {
return tail.cons(head);
}
/**
* Projects an immutable collection of this non-empty list.
*
* @return An immutable collection of this non-empty list.
*/
public Collection toCollection() {
return toList().toCollection();
}
/**
* Returns a function that takes a non-empty list to a list.
*
* @return A function that takes a non-empty list to a list.
*/
public static F, List> toList_() {
return NonEmptyList::toList;
}
/**
* Return a non-empty list with the given head and tail.
*
* @param head The first element of the new list.
* @param tail The remaining elements of the new list.
* @return A non-empty list with the given head and tail.
*/
public static NonEmptyList nel(final A head, final List tail) {
return new NonEmptyList<>(head, tail);
}
/**
* Constructs a non empty list from the given elements.
*
* @param head The first in the non-empty list.
* @param tail The elements to construct a list's tail with.
* @return A non-empty list with the given elements.
*/
@SafeVarargs public static NonEmptyList nel(final A head, final A... tail) {
return nel(head, List.list(tail));
}
/**
* Returns a function that puts an element into a non-empty list.
*
* @return A function that puts an element into a non-empty list.
*/
public static F> nel() {
return a -> nel(a);
}
/**
* Returns a potential non-empty list from the given list. A non-value is returned if the given list is empty.
*
* @param as The list to construct a potential non-empty list with.
* @return A potential non-empty list from the given list.
*/
public static Option> fromList(final List as) {
return as.isEmpty() ?
Option.none() :
some(nel(as.head(), as.tail()));
}
/**
* Concatenate (join) a non empty list of non empty lists.
*
* @param o The non empty list of non empty lists to join.
* @return A new non empty list that is the concatenation of the given lists.
*/
public static NonEmptyList join(final NonEmptyList> o) { return o.bind(identity()); }
/**
* Perform an equality test on this list which delegates to the .equals() method of the member instances.
* This is implemented with Equal.nonEmptyListEqual using the anyEqual rule.
*
* @param obj the other object to check for equality against.
* @return true if this list is equal to the provided argument
*/
@Override public boolean equals( final Object obj ) {
return Equal.equals0(NonEmptyList.class, this, obj, () -> Equal.nonEmptyListEqual(Equal.anyEqual()));
}
@Override public int hashCode() {
return Hash.nonEmptyListHash(Hash.anyHash()).hash(this);
}
@Override public String toString() { return Show.nonEmptyListShow(Show.anyShow()).showS(this); }
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy