Quick Index
Steps



Problem Statement


Use the same problem statement used for the algorithm problem

Convert the psuedocode solution to Java.





































































































Hints







































































































Solution


Solution Code
Use Solution Code (Simple)
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));
}