import java.util.Arrays;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.BiFunction;
/** QueryArray - read-only queryable array */
public class QueryArray<E> {
//------------------------------------------
// Object Structure (Instance Variables)
private final E[] elements;
//------------------------------------------
// Constructing
/** Construct new QueryArray from passed elements */
public static <T> QueryArray<T> from(T[] elements) {
return new QueryArray<>(elements);
}
/** Construct new QueryArray from passed elements */
private QueryArray(E[] elements) {
this.elements = elements;
}
//------------------------------------------
// Accessing (Core)
/** Returns nice display string */
@Override
public String toString() {
if (this.size() <= 4)
return Arrays.toString(this.elements);
return "Array Size -- " + this.size();
}
/** Iterates over elements in "this" object. For each element,
* performs actionFct (passing element being iterated on) */
public void forEach(Consumer<E> actionFct) {
for (E nextElem: this.elements)
actionFct.accept(nextElem);
}
/** Prints all elements to console, with newline after each */
public void printAll(String label) {
println(label);
if (this.size() == 0)
println("empty array");
else
this.forEach(nextElem -> println(nextElem.toString()));
}
// -----------------------------------------------------
//Specified Methods
/** Returns a new collection by selecting elements
* from "this.elements" where the selectFct outputs
* true when invoked */
public QueryArray<E> select(Function<E, Boolean> selectFct) {
int sz = this.size();
E[] array = arrayOfSize(sz);
int selectSz = 0;
for (E next: this.elements)
if (selectFct.apply(next))
array[selectSz++] = next;
return QueryArray.from(truncateArray(array, selectSz));
}
/** Returns a new collection containing all elements in
* the passed collection by rejecting those that yield
* "true" using the passed reject function. */
public QueryArray<E> reject(Function<E, Boolean> rejectFct) {
Function<E, Boolean> inverseFct
= (elem) -> !rejectFct.apply(elem);
return this.select(inverseFct);
}
/** Returns the index of the first match, or -1 if no match */
public int findFirst(Function<E, Boolean> matchFct) {
for (int i = 0; i < this.size(); i++)
if (matchFct.apply(this.elements[i]))
return i;
return -1;
}
/** Returns the index of the last match, or -1 if no match */
public int findLast(Function<E, Boolean> matchFct) {
for (int i = this.size() - 1; i >= 0; i--)
if (matchFct.apply(this.elements[i]))
return i;
return -1;
}
/** Returns a new QueryArray containing the elements of this list
* between the given index start (inclusive) and the given
* index stop (exclusive). */
public QueryArray<E> subList(int start, int stop) {
Function<Integer, String>
msgFct = (i) -> String.format("(subList) index %d is out of bounds", i);
this.validateIndex(start, msgFct);
this.validateIndex(stop - 1, msgFct);
E[] array = arrayOfSize(stop - start);
for (int i = start, j = 0; i < stop; i++, j++)
array[j] = this.get(i);
return QueryArray.from(array);
}
/** Returns the element at the passed zero-based index */
public E get(int index) {
this.validateIndex(index, i -> String.format("(get) index %d is out of bounds", i));
return this.elements[index];
}
/** Returns new QueryArray where mapFct is used to generate
* new elements from existing elements in "this" object */
public <T> QueryArray<T> map(Function<E, T> mapFct) {
//noinspection unchecked
int sz = this.size();
T[] array = arrayOfSize(sz);
for (int i = 0; i < sz; i++)
array[i] = mapFct.apply(this.get(i));
return QueryArray.from(array);
}
/** Accumulate a value by iterating over the collection
* and accumulating the next value using the fct */
public <T> T accumulate(BiFunction<T, E, T> fct, T initialValue) {
T accumulation = initialValue;
for (E each: this.elements)
accumulation = fct.apply(accumulation, each);
return accumulation;
}
// -----------------------------------------------------
//Helper Methods
/** Returns array of type "T" and of specified size */
@SuppressWarnings("unchecked")
public static <T> T[] arrayOfSize(int sz) {
return (T[]) new Object[sz];
}
/** Returns array that is passed array truncated to
* specified size */
public static <T> T[] truncateArray(T[] array, int size) {
T[] truncated = arrayOfSize(size);
for (int i = 0; i < size; i++)
truncated[i] = array[i];
return truncated;
}
public int size() {
return this.elements.length;
}
/** Validate index, throw exception if invalid */
private void validateIndex(int index, Function<Integer, String> exceptionMessageFct) {
if (!(index >= 0 && index < this.size()))
throw new RuntimeException(exceptionMessageFct.apply(index));
}
public static void println(Object o) {
System.out.println(o != null ? o.toString() : "null");
}
} _br_ _br_//_test_private void experiment() {
Shipment[] array = Shipment.generateSamples(10);
QueryArray<Shipment>
originalShipments = QueryArray.from(array),
shipments;
originalShipments.printAll("All Shipments");
shipments = originalShipments.select((each) -> each.getWeight() == 1);
shipments .printAll("-- Lighter Shipments --");
}
Use Solution Code (Advanced)
import java.util.Arrays;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.BiFunction;
/** QueryArray - read-only queryable array */
public class QueryArray<E> {
//------------------------------------------
// Object Structure (Instance Variables)
private final E[] elements;
//------------------------------------------
// Constructing
/** Construct new QueryArray from passed elements */
public static <T> QueryArray<T> from(T[] elements) {
return new QueryArray<>(elements);
}
/** Construct new QueryArray from passed elements */
private QueryArray(E[] elements) {
this.elements = elements;
}
//------------------------------------------
// Accessing (Core)
/** Returns nice display string */
@Override
public String toString() {
if (this.size() <= 4)
return Arrays.toString(this.elements);
return "Array Size -- " + this.size();
}
/** Iterates over elements in "this" object. For each element,
* performs actionFct (passing element being iterated on) */
public void forEach(Consumer<E> actionFct) {
for (E nextElem: this.elements)
actionFct.accept(nextElem);
}
/** Prints all elements to console, with newline after each */
public void printAll(String label) {
println(label);
if (this.size() == 0)
println("empty array");
else
this.forEach(nextElem -> println(nextElem.toString()));
}
// -----------------------------------------------------
//Specified Methods
/** Returns a new collection by selecting elements
* from "this.elements" where the selectFct outputs
* true when invoked */
public QueryArray<E> select(Function<E, Boolean> selectFct) {
int sz = this.size();
E[] array = arrayOfSize(sz);
int selectSz = 0;
for (E next: this.elements)
if (selectFct.apply(next))
array[selectSz++] = next;
return QueryArray.from(truncateArray(array, selectSz));
}
/** Returns a new collection containing all elements in
* the passed collection by rejecting those that yield
* "true" using the passed reject function. */
public QueryArray<E> reject(Function<E, Boolean> rejectFct) {
Function<E, Boolean> inverseFct
= (elem) -> !rejectFct.apply(elem);
return this.select(inverseFct);
}
/** Returns the index of the first match, or -1 if no match */
public int findFirst(Function<E, Boolean> matchFct) {
for (int i = 0; i < this.size(); i++)
if (matchFct.apply(this.elements[i]))
return i;
return -1;
}
/** Returns the index of the last match, or -1 if no match */
public int findLast(Function<E, Boolean> matchFct) {
for (int i = this.size() - 1; i >= 0; i--)
if (matchFct.apply(this.elements[i]))
return i;
return -1;
}
/** Returns a new QueryArray containing the elements of this list
* between the given index start (inclusive) and the given
* index stop (exclusive). */
public QueryArray<E> subList(int start, int stop) {
Function<Integer, String>
msgFct = (i) -> String.format("(subList) index %d is out of bounds", i);
this.validateIndex(start, msgFct);
this.validateIndex(stop - 1, msgFct);
E[] array = arrayOfSize(stop - start);
for (int i = start, j = 0; i < stop; i++, j++)
array[j] = this.get(i);
return QueryArray.from(array);
}
/** Returns the element at the passed zero-based index */
public E get(int index) {
this.validateIndex(index, i -> String.format("(get) index %d is out of bounds", i));
return this.elements[index];
}
/** Returns new QueryArray where mapFct is used to generate
* new elements from existing elements in "this" object */
public <T> QueryArray<T> map(Function<E, T> mapFct) {
//noinspection unchecked
int sz = this.size();
T[] array = arrayOfSize(sz);
for (int i = 0; i < sz; i++)
array[i] = mapFct.apply(this.get(i));
return QueryArray.from(array);
}
/** Accumulate a value by iterating over the collection
* and accumulating the next value using the fct */
public <T> T accumulate(BiFunction<T, E, T> fct, T initialValue) {
T accumulation = initialValue;
for (E each: this.elements)
accumulation = fct.apply(accumulation, each);
return accumulation;
}
// -----------------------------------------------------
//Helper Methods
/** Returns array of type "T" and of specified size */
@SuppressWarnings("unchecked")
public static <T> T[] arrayOfSize(int sz) {
return (T[]) new Object[sz];
}
/** Returns array that is passed array truncated to
* specified size */
public static <T> T[] truncateArray(T[] array, int size) {
T[] truncated = arrayOfSize(size);
for (int i = 0; i < size; i++)
truncated[i] = array[i];
return truncated;
}
public int size() {
return this.elements.length;
}
/** Validate index, throw exception if invalid */
private void validateIndex(int index, Function<Integer, String> exceptionMessageFct) {
if (!(index >= 0 && index < this.size()))
throw new RuntimeException(exceptionMessageFct.apply(index));
}
public static void println(Object o) {
System.out.println(o != null ? o.toString() : "null");
}
} _br_ _br_//_test_private void experiment() {
Shipment[] array = Shipment.generateSamples(2000);
QueryArray<Shipment>
originalShipments = QueryArray.from(array),
shipments;
Function<Shipment, Boolean> isHeavyFct, isLongDistanceFct, isLocalFct;
isHeavyFct = (shipment) -> shipment.getWeight() >= 5;
isLongDistanceFct = (shipment) -> shipment.getDistance() >= 500;
isLocalFct = (shipment) -> {
long zip = shipment.getZipCode();
return zip >= 55443 && zip <= 55447;
};
shipments = originalShipments.select(isHeavyFct);
shipments = shipments.reject(isLongDistanceFct);
shipments = shipments.select(isLocalFct);
shipments.printAll("-- Selected Shipments --");
Long weight, distance;
Double price;
weight = shipments.accumulate((sum, each) -> sum + each.getWeight(), 0L);
distance = shipments.accumulate((sum, each) -> sum + each.getDistance(), 0L);
price = shipments.accumulate((sum, each) -> sum + each.getPrice(), 0.0);
println("Total Weight (pounds): " + weight);
println("Total Distance (miles): " + distance);
println("Total Price $: " + String.format("%.2f", price));
}