com.github.methylene.lists.LookupList Maven / Gradle / Ivy
Show all versions of sym Show documentation
package com.github.methylene.lists;
import com.github.methylene.sym.Permutation;
import java.lang.reflect.Array;
import java.util.*;
/**
* LookupLists are immutable, null-rejecting, array based implementation of {@link java.util.List}
* that are optimized for search. Its {@code indexOf}, {@code lastIndexOf} and {@code contains}
* methods will often run faster than other array based list implementations.
*
* LookupList stores a sorted array internally, so binary search can be used.
*
*
* Consequentially, the list can only contain things that can be compared:
* primitives or Comparables. Building a list from arbitrary objects is also possible if a suitable Comparator
* is provided.
*
* Instances of this list are slower to create and use more memory than {@link java.util.ArrayList}.
* This is because the backing array has to be sorted when the list is created, and for each element in the list,
* an extra 8 bytes (two ints) are used to store its original position.
*
* The speedup of the search methods depends on the size of the list, and also on the cost of the
* {@code equals} method of its elements.
*/
public abstract class LookupList extends AbstractList implements RandomAccess {
static final int[] EMPTY_INT_ARRAY = new int[0];
protected final Permutation unsort;
protected final Permutation sort;
static int checkNonnegative(int i) {
if (i < 0)
throw new IllegalArgumentException("negative number is not allowed");
return i;
}
protected LookupList(Permutation sort, Permutation unsort) {
this.sort = sort;
this.unsort = unsort;
}
protected LookupList(Permutation sort) {
this(sort, sort.invert());
}
/**
* Return a new list that contains the elements of this list in natural order.
* @return the sorted list
*/
public abstract List sort();
/**
* Returns a new list that contains the elements of this list in natural order,
* with duplicates removed.
* @return the unique sorted list
*/
public abstract List sortUnique();
/**
* Group the elements in this list.
* This returns a map where each distinct value in the list is mapped to an array of all the indexes
* where it appears. This array of indexes is in ascending order.
* @return the grouped list
*/
public abstract Map group();
public abstract LookupList shuffle(Permutation p);
public abstract boolean isUnique();
public abstract boolean isSorted();
/**
* Find at most {@code size} indexes {@code i} where
*
* this.get(i).equals(el)
*
* The return value is in natural order.
* This method could be used to find duplicates in the list as follows:
*
* public E findDuplicate(LookupList list) {
* for (E el: list) {
* if (list.indexOf(el, 2).length == 2) {
* return el;
* }
* }
* return null;
* }
*
* If {@code size < 0}, all indexes of {@code el} are returned.
* If {@code el} is not in the list, this returns an empty array.
* @param el an object
* @param size a number
* @return an array of length {@code size} or less, or an array of all indexes of {@code el} if {@code size < 0}
*/
public abstract int[] indexOf(E el, int size);
/**
* Creates a primitive list from the given input.
* @param a an array
* @return a list representation of the input
*/
@SuppressWarnings("unchecked")
public static LookupList of(int... a) {
switch (a.length) {
case 0: return (LookupList) EmptyLookupList.INSTANCE;
case 1: return new SingleElementLookupList(a[0]);
default: return IntList.createNewList(a, Permutation.sort(a));
}
}
/**
* Creates a primitive list from the given input.
* @param a an array
* @return a list representation of the input
*/
@SuppressWarnings("unchecked")
public static LookupList of(long... a) {
switch (a.length) {
case 0: return (LookupList) EmptyLookupList.INSTANCE;
case 1: return new SingleElementLookupList(a[0]);
default: return LongList.createNewList(a, Permutation.sort(a));
}
}
/**
* Creates a primitive list from the given input.
* @param a an array
* @return a list representation of the input
*/
@SuppressWarnings("unchecked")
public static LookupList of(byte... a) {
switch (a.length) {
case 0: return (LookupList) EmptyLookupList.INSTANCE;
case 1: return new SingleElementLookupList(a[0]);
default: return ByteList.createNewList(a, Permutation.sort(a));
}
}
/**
* Creates a primitive list from the given input.
* @param a an array
* @return a list representation of the input
*/
@SuppressWarnings("unchecked")
public static LookupList of(char... a) {
switch (a.length) {
case 0: return (LookupList) EmptyLookupList.INSTANCE;
case 1: return new SingleElementLookupList(a[0]);
default: return CharList.createNewList(a, Permutation.sort(a));
}
}
/**
* Creates a primitive list from the given input.
* @param a an array
* @return a list representation of the input
*/
@SuppressWarnings("unchecked")
public static LookupList of(float... a) {
switch (a.length) {
case 0: return (LookupList) EmptyLookupList.INSTANCE;
case 1: return new SingleElementLookupList(a[0]);
default: return FloatList.createNewList(a, Permutation.sort(a));
}
}
/**
* Creates a primitive list from the given input.
* @param a an array
* @return a list representation of the input
*/
@SuppressWarnings("unchecked")
public static LookupList of(double... a) {
switch (a.length) {
case 0: return (LookupList) EmptyLookupList.INSTANCE;
case 1: return new SingleElementLookupList(a[0]);
default: return DoubleList.createNewList(a, Permutation.sort(a));
}
}
/**
* Creates a primitive list from the given input.
* @param a an array
* @return a list representation of the input
*/
@SuppressWarnings("unchecked")
public static LookupList of(short... a) {
switch (a.length) {
case 0: return (LookupList) EmptyLookupList.INSTANCE;
case 1: return new SingleElementLookupList(a[0]);
default: return ShortList.createNewList(a, Permutation.sort(a));
}
}
/**
* Returns the empty list.
* @return the empty list
*/
@SuppressWarnings("unchecked")
public static LookupList of() {
return (LookupList) EmptyLookupList.INSTANCE;
}
/**
* Creates a list from the given input.
* @throws java.lang.NullPointerException if the input contains a {@code null} element
*/
public static LookupList of(E e0) {
return new SingleElementLookupList(e0);
}
/**
* Creates a list from the given input.
* @throws java.lang.NullPointerException if the input contains a {@code null} element
*/
public static LookupList of(E e0, E e1) {
return new ComparableList.Builder(2).add(e0).add(e1).build();
}
/**
* Creates a list from the given input.
*
* @throws java.lang.NullPointerException if the input contains a {@code null} element
*/
public static LookupList of(E e0, E e1, E e2) {
return new ComparableList.Builder(3).add(e0).add(e1).add(e2).build();
}
/**
* Creates a list from the given input.
*
* @throws java.lang.NullPointerException if the input contains a {@code null} element
*/
public static LookupList of(E e0, E e1, E e2, E e3) {
return new ComparableList.Builder(4).add(e0).add(e1).add(e2).add(e3).build();
}
/**
* Creates a list from the given input.
*
* @throws java.lang.NullPointerException if the input contains a {@code null} element
*/
public static LookupList of(E e0, E e1, E e2, E e3, E e4) {
return new ComparableList.Builder(5).add(e0).add(e1).add(e2).add(e3).add(e4).build();
}
/**
* Creates a list from the given input.
*
* @throws java.lang.NullPointerException if the input contains a {@code null} element
*/
public static LookupList of(E e0, E e1, E e2, E e3, E e4, E e5) {
return new ComparableList.Builder(6).add(e0).add(e1).add(e2).add(e3).add(e4).add(e5).build();
}
/**
* Creates a list from the given input.
*
* @throws java.lang.NullPointerException if the input contains a {@code null} element
*/
public static LookupList of(E e0, E e1, E e2, E e3, E e4, E e5, E e6) {
return new ComparableList.Builder(7).add(e0).add(e1).add(e2).add(e3).add(e4).add(e5).add(e6).build();
}
/**
* Creates a list from the given input.
*
* @throws java.lang.NullPointerException if the input contains a {@code null} element
*/
public static LookupList of(E e0, E e1, E e2, E e3, E e4, E e5, E e6, E e7) {
return new ComparableList.Builder(8).add(e0).add(e1).add(e2).add(e3).add(e4).add(e5).add(e6).add(e7).build();
}
/**
* Creates a list from the given input.
*
* @throws java.lang.NullPointerException if the input contains a {@code null} element
*/
public static LookupList of(E e0, E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) {
return new ComparableList.Builder(9).add(e0).add(e1).add(e2).add(e3).add(e4).add(e5).add(e6).add(e7).add(e8).build();
}
/**
* Creates a list from the given input.
*
* @throws java.lang.NullPointerException if the input contains a {@code null} element
*/
public static LookupList of(E e0, E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) {
return new ComparableList.Builder(10).add(e0).add(e1).add(e2).add(e3).add(e4).add(e5).add(e6).add(e7).add(e8).add(e9).build();
}
/**
* Creates a list from the given input.
*
* @throws java.lang.NullPointerException if the input contains a {@code null} element
*/
public static LookupList of(E e0, E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) {
return new ComparableList.Builder(11).add(e0).add(e1).add(e2).add(e3).add(e4).add(e5).add(e6).add(e7).add(e8).add(e9).add(e10).build();
}
/**
* Creates a list from the given input.
*
* @throws java.lang.NullPointerException if the input contains a {@code null} element
*/
public static LookupList of(E e0, E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10, E... es) {
return new ComparableList.Builder(11 + es.length).add(e0).add(e1).add(e2).add(e3).add(e4).add(e5).add(e6).add(e7).add(e8).add(e9).add(e10).addAll(es).build();
}
/**
* Creates a list from the given input.
*
* @throws java.lang.NullPointerException if the input contains a {@code null} element
*/
@SuppressWarnings("unchecked")
public static LookupList copyOf(E[] a) {
switch (a.length) {
case 0: return (LookupList) EmptyLookupList.INSTANCE;
case 1: return new SingleElementLookupList(a[0]);
default: return ComparableList.createNewList(a, Permutation.sort(a));
}
}
/**
* Create a new list from the given input. If the input is already an instance of LookupList, it is returned unchanged.
* @param list a list
* @return a LookupList
*/
@SuppressWarnings("unchecked")
public static LookupList copyOf(Collection list) {
if (list instanceof LookupList)
return (LookupList) list;
switch (list.size()) {
case 0: return (LookupList) EmptyLookupList.INSTANCE;
case 1: return new SingleElementLookupList(list.iterator().next());
default:
ComparableList.Builder builder = new ComparableList.Builder(list.size());
builder.addAll(list);
return builder.build();
}
}
/**
* Create a new list from the given input.
* @param iterable a iterable
* @return a LookupList
*/
public static LookupList copyOf(Iterable iterable) {
if (iterable instanceof LookupList)
return (LookupList) iterable;
return copyOf(iterable.iterator());
}
/**
* Create a new list from the given input.
* @param iterator a iterator
* @return a LookupList
*/
@SuppressWarnings("unchecked")
public static LookupList copyOf(Iterator iterator) {
if (!iterator.hasNext())
return (LookupList) EmptyLookupList.INSTANCE;
E first = iterator.next();
if (!iterator.hasNext())
return new SingleElementLookupList(first);
ComparableList.Builder builder = new ComparableList.Builder();
builder.add(first);
while (iterator.hasNext())
builder.add(iterator.next());
return builder.build();
}
/**
* Creates a list from the given input.
* @param comparator a comparator
* @param a an array
* @return a list representation of the input
* @throws java.lang.NullPointerException if the input contains a {@code null} element
*/
@SuppressWarnings("unchecked")
public static LookupList copyOf(Comparator comparator, E[] a) {
if (comparator == null)
throw new IllegalArgumentException("comparator can not be null");
switch (a.length) {
case 0: return (LookupList) EmptyLookupList.INSTANCE;
case 1: return new SingleElementLookupList(a[0]);
default: return ComparatorList.createNewList(comparator, a, Permutation.sort(a, comparator));
}
}
/**
* Create a new list from the given input. If the input is already an instance of LookupList, it is returned unchanged.
* @param comparator a comparator
* @param list a list
* @return a LookupList
*/
@SuppressWarnings("unchecked")
public static LookupList copyOf(Comparator comparator, Collection list) {
if (list instanceof LookupList)
return (LookupList) list;
switch (list.size()) {
case 0: return (LookupList) EmptyLookupList.INSTANCE;
case 1: return new SingleElementLookupList(list.iterator().next());
default:
ComparatorList.Builder builder = new ComparatorList.Builder(comparator, list.size());
builder.addAll(list);
return builder.build();
}
}
/**
* Create a new list from the given input.
* @param comparator a comparator
* @param iterable a iterable
* @return a LookupList
*/
public static LookupList copyOf(Comparator comparator, Iterable iterable) {
if (iterable instanceof LookupList)
return (LookupList) iterable;
return copyOf(comparator, iterable.iterator());
}
/**
* Create a new list from the given input.
* @param comparator a comparator
* @param iterator a iterator
* @return a LookupList
*/
@SuppressWarnings("unchecked")
public static LookupList copyOf(Comparator comparator, Iterator iterator) {
if (!iterator.hasNext())
return (LookupList) EmptyLookupList.INSTANCE;
E first = iterator.next();
if (!iterator.hasNext())
return new SingleElementLookupList(first);
ComparatorList.Builder builder = new ComparatorList.Builder(comparator);
builder.add(first);
while (iterator.hasNext())
builder.add(iterator.next());
return builder.build();
}
/**
* Create a list builder.
* @param comparator a comparator
* @return a new builder
*/
public static ListBuilder builder(Comparator comparator) {
return new ComparatorList.Builder(comparator);
}
/**
* Create a list builder.
* @param comparator a comparator
* @param initialCapacity initial builder capacity
* @return a new builder
*/
public static ListBuilder builder(Comparator comparator, int initialCapacity) {
return new ComparatorList.Builder(comparator, initialCapacity);
}
/**
* Create a list builder.
* @return a new builder
*/
public static ListBuilder builder() {
return new ComparableList.Builder();
}
/**
* Create a list builder.
* @param initialCapacity initial builder capacity
* @return a new builder
*/
public static ListBuilder builder(int initialCapacity) {
return new ComparableList.Builder(initialCapacity);
}
}