The util class to find all the indexes on an element into a Collection supports forward and reverse lookup starting from a given index along with changing the Collection the element’s index is to be found into.
A convoluted implementation of Builder design pattern starting from the simplest implementation in the NextIndex class having a static factory method returning a NextIndex.Lookup instance that is a variation of factory design pattern implementation exposing forward and reverse methods altering its internal state, to setup the lookup direction, without exposing the change outside of the instance, methods that build and set in a filed a NextIndex.Explorer instance using fixed or flexible build semantic supported by the NextIndex.Explorer’s available variations of builder design pattern implementations to support defining exploring attributes in a fixed order...
Explorer.fixed().semantic().builder()
.from(() -> this.fromIndex)
.to(() -> this.source.size())
.bounder((index, bound) -> index < bound)
.incrementer((index) -> ++index)
.absent(() -> -1)
.newIt()
.get();
...or randomly...
Explorer.from(() -> this.fromIndex > 0 ? this.fromIndex : this.source.size() - 1)
.absent(() -> 1)
.incrementer((index) -> --index)
.bounder((index, bound) -> index >= bound)
.to(() -> 0)
.newIt()
.get();
...in any possible sequence...
Explorer.from(() -> this.fromIndex > 0 ? this.fromIndex : this.source.size() - 1)
.incrementer((index) -> --index)
.absent(() -> 1)
.bounder((index, bound) -> index >= bound)
.to(() -> 0)
.newIt()
.get();
Thread safeness concern could be addressed by each Thread using its own instance of NextIndex.Lookup class...
//TODO add package statement
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
public class NextIndex {
public static <T> Lookup<T> of(T element) {
return new NextIndex.Lookup<T>(element);
}
public static class Lookup<T> {
private T element;
private List<T> source = new ArrayList<T>();
private Integer fromIndex = 0;
private Explorer<Integer> explorer = forwardExplorer();
public Lookup(T element) { this.element = element; }
public <U extends Collection<T>> Lookup<T> into(U source) {
if (source == null) { return this; }
this.source = new ArrayList<>(source);
return this;
}
public Lookup<T> fromIndex(int index) {
this.fromIndex = index;
return this;
}
private Explorer<Integer> forwardExplorer() {
return Explorer.fixed().semantic().builder()
.from(() -> this.fromIndex)
.to(() -> this.source.size())
.bounder((index, bound) -> index < bound)
.incrementer((index) -> ++index)
.absent(() -> -1)
.newIt()
.get();
}
public Lookup<T> forward() {
this.explorer = forwardExplorer();
return this;
}
public Lookup<T> reverse() {
this.explorer = Explorer.from(() -> this.fromIndex > 0 ? this.fromIndex
: this.source.size() - 1)
.to(() -> 0)
.bounder((index, bound) -> index >= bound)
.incrementer((index) -> --index)
.absent(() -> 1)
.newIt()
.get();
return this;
}
public int absolute() {
int index = this.explorer.absent();
if (fromIndex < 0 || fromIndex > this.source.size()) { return index; }
for (int i = this.explorer.from()
; this.explorer.inbound(i, this.explorer.to())
; i = this.explorer.increment(i)) {
if (this.element == this.source.get(i)
|| this.element.equals(this.source.get(i))) {
index = i;
break;
}
}
return index;
}
public int relative() {
int index = this.explorer.absent();
if (fromIndex < 0 || fromIndex > this.source.size()) { return index; }
int i = this.explorer.from();
while (this.explorer.inbound(i, this.explorer.to())) {
if (this.element == this.source.get(i)
|| this.element.equals(this.source.get(i))) {
index = i - this.fromIndex;
break;
}
i = this.explorer.increment(i);
}
return index;
}
}
public static class Explorer<U> {
private Supplier<U> from;
private Supplier<U> to;
private Supplier<U> absent;
private BiFunction<U, U, Boolean> bounder;
private Function<U, U> incrementer;
private Explorer(Supplier<U> start, Supplier<U> bound) {
this.from = start;
this.to = bound;
}
private Explorer(Supplier<U> start
, Supplier<U> bound
, BiFunction<U, U, Boolean> bounder
, Function<U, U> incrementer
, Supplier<U> absent) {
this.from = start;
this.to = bound;
this.bounder = bounder;
this.incrementer = incrementer;
this.absent = absent;
}
public U from() { return this.from.get(); }
public U to() { return this.to.get(); }
public U absent() { return this.absent.get(); }
public boolean inbound(U index, U bound) {
return this.bounder.apply(index, bound);
}
public U increment(U index) {
return this.incrementer.apply(index);
}
public static <T> Explorer.Builder<T> from(Supplier<T> start) {
return new Explorer.Builder<T>(start);
}
public static Explorer.SemanticSource fixed() { return new Explorer.SemanticSource(); }
public static class SemanticSource {
private SemanticSource() {}
public Explorer.BuilderSource semantic() { return new Explorer.BuilderSource(); }
}
public static class BuilderSource {
private BuilderSource() {}
public BuilderFactory builder() { return new Explorer.BuilderFactory(); }
}
public static class BuilderFactory {
private BuilderFactory() {}
public <U> Explorer.Boundry<U> from(Supplier<U> from) {
return new Explorer.Boundry<U>(from);
}
}
private static abstract class Newer<K> {
abstract Optional<Explorer<K>> newIt();
}
public static class Boundry<K> extends Newer<K> {
public static <U> Boundry<U> from(Supplier<U> from) {
return new Explorer.Boundry<U>(from);
}
private Supplier<K> from;
private Supplier<K> to;
private Boundry(Supplier<K> from) { this.from = from; }
public Explorer.Bounder<K> to(Supplier<K> to) {
this.to = to;
return Explorer.Bounder.bound(this);
}
Optional<Explorer<K>> newIt() {
if (from == null || to == null ) { return Optional.empty(); }
return Optional.of(new Explorer<K>(from, to));
}
}
public static class Bounder<K> extends Newer<K> {
public static <U> Bounder<U> bound(Explorer.Boundry<U> boundry) {
return new Explorer.Bounder<>(boundry);
}
private Boundry<K> boundry;
private BiFunction<K, K, Boolean> bounder;
private Bounder(Boundry<K> boundry) {
this.boundry = boundry;
}
public Explorer.Incrementer<K> bounder(BiFunction<K, K, Boolean> bounder) {
this.bounder = bounder;
return Explorer.Incrementer.incremented(this);
}
Optional<Explorer<K>> newIt() {
if ( bounder == null) { return Optional.empty(); }
return this.boundry
.newIt()
.map(explorer -> {
explorer.bounder = this.bounder;
return explorer;
});
}
}
public static class Incrementer<K> extends Newer<K> {
public static <U> Explorer.Incrementer<U> incremented(Bounder<U> bounder) {
return new Explorer.Incrementer<U>(bounder);
}
private Bounder<K> bounder;
private Function<K, K> incrementer;
private Incrementer(Bounder<K> bounder) { this.bounder = bounder; }
public Explorer.Absent<K> incrementer(Function<K, K> incrementer) {
this.incrementer = incrementer;
return Explorer.Absent.of(this);
}
Optional<Explorer<K>> newIt() {
if (incrementer == null) { return Optional.empty(); }
return this.bounder
.newIt()
.map(explorer -> {
explorer.incrementer = this.incrementer;
return explorer;
});
}
}
public static class Absent<K> extends Newer<K> {
public static <U> Explorer.Absent<U> of(Explorer.Incrementer<U> incrementer) {
return new Explorer.Absent<U>(incrementer);
}
private Incrementer<K> incrementer;
private Supplier<K> absent;
private Absent(Incrementer<K> incrementer) {
this.incrementer = incrementer;
}
public Explorer.FixedSemanticBuilder<K> absent(Supplier<K> absent) {
this.absent = absent;
return Explorer.FixedSemanticBuilder.of(this);
}
Optional<Explorer<K>> newIt() {
if (absent == null) { return Optional.empty(); }
return this.incrementer
.newIt()
.map(explorer -> {
explorer.absent = this.absent;
return explorer;
});
}
}
public static class FixedSemanticBuilder<K> extends Newer<K> {
private Absent<K> absent;
private FixedSemanticBuilder(Absent<K> absent) {
this.absent = absent;
}
public static <R> FixedSemanticBuilder<R> of(Absent<R> absent) {
return new Explorer.FixedSemanticBuilder<R>(absent);
}
public Optional<Explorer<K>> newIt() { return this.absent.newIt(); }
}
public static class Builder<U> {
private Supplier<U> from;
private Supplier<U> to;
private Supplier<U> absent;
private BiFunction<U, U, Boolean> bounder;
private Function<U, U> incrementer;
public Builder(Supplier<U> start) {
this.from = start;
}
public Explorer.Builder<U> to(Supplier<U> bound) {
this.to = bound;
return this;
}
public Explorer.Builder<U> bounder(BiFunction<U, U, Boolean> bounder) {
this.bounder = bounder;
return this;
}
public Explorer.Builder<U> incrementer(Function<U, U> incrementer) {
this.incrementer = incrementer;
return this;
}
public Explorer.Builder<U> absent(Supplier<U> absent) {
this.absent = absent;
return this;
}
public Optional<Explorer<U>> newIt() {
if (from == null || to == null || bounder == null || incrementer == null) {
return Optional.empty();
}
return Optional.of(new Explorer<U>(from, to, bounder, incrementer, absent));
}
}
}
}
Usage depicted by...
//TODO add package statement
import java.util.ArrayList;
import java.util.List;
public class IndexLookupApplication {
public static void main(String[] args) {
int element = 1;
List<Integer> list = List.of(1, 2, 3, 1, 2, 3, 1, 2, 3);
List<Integer> differentList = List.of(3, 2, 1, 3, 2, 1, 3, 2, 1);
forwardLookup(element, list, differentList);
System.out.println("");
System.out.println("");
System.out.println("");
reverseLookup(element, list, differentList);
}
private static void forwardLookup(int element, List<Integer> list, List<Integer> differentList) {
System.out.println("********** Forward lookup **********");
NextIndex.Lookup<Integer> indexLookup = NextIndex.of(element);
int firstIndexOfIntoAList = indexLookup.into(list).absolute();
int secondAbsoluteIndexOfIntoAList = indexLookup.fromIndex(firstIndexOfIntoAList + 1).absolute();
int secondRelativeIndexOfIntoAList = indexLookup.relative();
int indexOfFromPreviousIndexIntoDifferentList = indexLookup.into(differentList).absolute();
int indexOfIntoDifferentList = indexLookup.into(differentList).fromIndex(0).absolute();
String listToString = list.toString();
System.out.println("list of elements " + listToString);
System.out.println(String.format("1st absolute index of element %d is %d", element, firstIndexOfIntoAList));
System.out.println(String.format("2nd absolute index of element %d is %d", element, secondAbsoluteIndexOfIntoAList));
System.out.println(String.format("1st relative index of element %d starting from index %d is %d", element, (firstIndexOfIntoAList + 1), secondRelativeIndexOfIntoAList));
System.out.println(String.format("different list of elements %s", differentList.toString()));
System.out.println(String.format("1st absolute index of element %d into a different list from previous index is %d",
element, indexOfFromPreviousIndexIntoDifferentList));
System.out.println(String.format("1st absolute index of element %d into a different list from the start is %d", element,
indexOfIntoDifferentList));
Integer indexOf = indexLookup.into(list).fromIndex(0).absolute();
List<Integer> indexes = new ArrayList<>();
while (indexOf > -1) {
indexes.add(indexOf);
indexOf = indexLookup.fromIndex(indexOf + 1).absolute();
}
System.out.println(
String.format("element's %d indexes in list %s is %s", element, listToString, indexes.toString()));
}
private static void reverseLookup(int element, List<Integer> list, List<Integer> differentList) {
System.out.println("********** Reversed lookup **********");
NextIndex.Lookup<Integer> indexLookup = NextIndex.of(element).reverse();
int firstIndexOfIntoAList = indexLookup.into(list).absolute();
int secondAbsoluteIndexOfIntoAList = indexLookup.fromIndex(firstIndexOfIntoAList - 1).absolute();
int secondRelativeIndexOfIntoAList = indexLookup.relative();
int indexOfFromPreviousIndexIntoDifferentList = indexLookup.into(differentList).absolute();
int indexOfIntoDifferentList = indexLookup.into(differentList).fromIndex(0).absolute();
String listToString = list.toString();
System.out.println("list of elements " + listToString);
System.out.println(String.format("1st absolute index of element %d is %d", element, firstIndexOfIntoAList));
System.out.println(String.format("2nd absolute index of element %d is %d", element, secondAbsoluteIndexOfIntoAList));
System.out.println(String.format("1st relative index of element %d starting from index %d is %d", element, (firstIndexOfIntoAList - 1), secondRelativeIndexOfIntoAList));
System.out.println(String.format("different list of elements %s", differentList.toString()));
System.out.println(String.format("1st absolute index of element %d into a different list from previous index is %d",
element, indexOfFromPreviousIndexIntoDifferentList));
System.out.println(String.format("1st absolute index of element %d into a different list from the start is %d", element,
indexOfIntoDifferentList));
Integer indexOf = indexLookup.into(list).fromIndex(0).absolute();
List<Integer> indexes = new ArrayList<>();
while (indexOf > 0) {
indexes.add(indexOf);
indexOf = indexLookup.fromIndex(indexOf - 1).absolute();
}
System.out.println(
String.format("element's %d indexes in list %s is %s", element, listToString, indexes.toString()));
}
}]
...with the output...
********** Forward lookup **********
list of elements [1, 2, 3, 1, 2, 3, 1, 2, 3]
1st absolute index of element 1 is 0
2nd absolute index of element 1 is 3
1st relative index of element 1 starting from index 1 is 2
different list of elements [3, 2, 1, 3, 2, 1, 3, 2, 1]
1st absolute index of element 1 into a different list from previous index is 2
1st absolute index of element 1 into a different list from the start is 2
element's 1 indexes in list [1, 2, 3, 1, 2, 3, 1, 2, 3] is [0, 3, 6]
********** Reversed lookup **********
list of elements [1, 2, 3, 1, 2, 3, 1, 2, 3]
1st absolute index of element 1 is 6
2nd absolute index of element 1 is 3
1st relative index of element 1 starting from index 5 is -2
different list of elements [3, 2, 1, 3, 2, 1, 3, 2, 1]
1st absolute index of element 1 into a different list from previous index is 5
1st absolute index of element 1 into a different list from the start is 8
element's 1 indexes in list [1, 2, 3, 1, 2, 3, 1, 2, 3] is [6, 3]
This code review request is an after thought of Sequentially bidirectional find the indexes of an element into a collection (second thought)