arrays.java
/*
* Java Genetic Algorithm Library (@__identifier__@).
* Copyright (c) @__year__@ Franz Wilhelmstötter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Author:
* Franz Wilhelmstötter (franz.wilhelmstoetter@gmx.at)
*/
package org.jenetics.util;
import static java.util.Objects.requireNonNull;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* Static helper methods concerning arrays.
*
* @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
* @since 1.0
* @version 2.0 — <em>$Date: 2014-03-31 $</em>
*/
public final class arrays extends StaticObject {
private arrays() {}
/**
* Unified method for calculating the hash code of every {@link Seq}
* implementation. The hash code is defined as followed:
*
* [code]
* int hashCode = 1;
* final Iterator<E> it = seq.iterator();
* while (it.hasNext()) {
* final E obj = it.next();
* hashCode = 31*hashCode + (obj == null ? 0 : obj.hashCode());
* }
* [/code]
*
* @see Seq#hashCode()
* @see List#hashCode()
*
* @param seq the sequence to calculate the hash code for.
* @return the hash code of the given sequence.
*/
public static int hashCode(final Seq<?> seq) {
int hash = 1;
for (Object element : seq) {
hash = 31*hash + (element == null ? 0: element.hashCode());
}
return hash;
}
/**
* Unified method for compare to sequences for equality.
*
* @see Seq#equals(Object)
*
* @param seq the sequence to test for equality.
* @param obj the object to test for equality with the sequence.
* @return {@code true} if the given objects are sequences and contain the
* same objects in the same order, {@code false} otherwise.
*/
public static boolean equals(final Seq<?> seq, final Object obj) {
if (obj == seq) {
return true;
}
if (!(obj instanceof Seq<?>)) {
return false;
}
final Seq<?> other = (Seq<?>)obj;
boolean equals = (seq.length() == other.length());
for (int i = seq.length(); equals && --i >= 0;) {
final Object element = seq.get(i);
if (element != null) {
equals = element.equals(other.get(i));
} else {
equals = other.get(i) == null;
}
}
return equals;
}
/**
* Calls the sort method on the {@link Arrays} class.
*
* @param <T> the array element type
* @param array the array to sort
* @return the sorted input array, for command chaining
* @throws NullPointerException if the give array is {@code null}.
* @throws UnsupportedOperationException if the array is sealed
* ({@code array.isSealed() == true}).
*/
public static <T extends Object & Comparable<? super T>> MSeq<T>
sort(final MSeq<T> array)
{
Collections.sort(array.asList());
return array;
}
/**
* Test whether the given array is sorted in ascending order.
*
* @param <T> the array element type
* @param seq the array to test.
* @return {@code true} if the given {@code array} is sorted in ascending
* order, {@code false} otherwise.
* @throws NullPointerException if the given array or one of it's element is
* {@code null}.
*/
public static <T extends Object & Comparable<? super T>>
boolean isSorted(final Seq<T> seq)
{
boolean sorted = true;
for (int i = 0, n = seq.length() - 1; i < n && sorted; ++i) {
sorted = seq.get(i).compareTo(seq.get(i + 1)) <= 0;
}
return sorted;
}
/**
* Test whether the given array is sorted in ascending order. The order of
* the array elements is defined by the given comparator.
*
* @param <T> the array element type
* @param seq the array to test.
* @param comparator the comparator which defines the order.
* @return {@code true} if the given {@code array} is sorted in ascending
* order, {@code false} otherwise.
* @throws NullPointerException if the given array or one of it's element or
* the comparator is {@code null}.
*/
public static <T> boolean isSorted(
final Seq<T> seq, final Comparator<? super T> comparator
) {
boolean sorted = true;
for (int i = 0, n = seq.length() - 1; i < n && sorted; ++i) {
sorted = comparator.compare(seq.get(i), seq.get(i + 1)) <= 0;
}
return sorted;
}
/**
* Return a array with the indexes of the partitions of an array with the
* given size. The length of the returned array is {@code min(size, prts) + 1}.
* <p>
* Some examples:
* <pre>
* partition(10, 3): [0, 3, 6, 10]
* partition(15, 6): [0, 2, 4, 6, 9, 12, 15]
* partition(5, 10): [0, 1, 2, 3, 4, 5]
* </pre>
*
* The following examples prints the start index (inclusive) and the end
* index (exclusive) of the {@code partition(15, 6)}.
* [code]
* int[] parts = partition(15, 6);
* for (int i = 0; i < parts.length - 1; ++i) {
* System.out.println(i + ": " + parts[i] + "\t" + parts[i + 1]);
* }
* [/code]
* <pre>
* 0: 0 2
* 1: 2 4
* 2: 4 6
* 3: 6 9
* 4: 9 12
* 5: 12 15
* </pre>
*
* This example shows how this can be used in an concurrent environment:
* [code]
* try (final Concurrency c = Concurrency.start()) {
* final int[] parts = arrays.partition(population.size(), _maxThreads);
*
* for (int i = 0; i < parts.length - 1; ++i) {
* final int part = i;
* c.execute(new Runnable() { @Override public void run() {
* for (int j = parts[part + 1]; --j >= parts[part];) {
* population.get(j).evaluate();
* }
* }});
* }
* }
* [/code]
*
* @param size the size of the array to partition.
* @param parts the number of parts the (virtual) array should be partitioned.
* @return the partition array with the length of {@code min(size, parts) + 1}.
* @throws IllegalArgumentException if {@code size} or {@code p} is less than one.
*/
public static int[] partition(final int size, final int parts) {
if (size < 1) {
throw new IllegalArgumentException(
"Size must greater than zero: " + size
);
}
if (parts < 1) {
throw new IllegalArgumentException(
"Number of partitions must greater than zero: " + parts
);
}
final int pts = Math.min(size, parts);
final int[] partition = new int[pts + 1];
final int bulk = size/pts;
final int rest = size%pts;
assert ((bulk*pts + rest) == size);
for (int i = 0, n = pts - rest; i < n; ++i) {
partition[i] = i*bulk;
}
for (int i = 0, n = rest + 1; i < n; ++i) {
partition[pts - rest + i] = (pts - rest)*bulk + i*(bulk + 1);
}
return partition;
}
/**
* Iterates over all elements of the given {@code array} as long as the
* {@code predicate} returns {@code true} (which means <i>continue</i>) and
* returns the index the iteration has been interrupted. -1 is returned if
* all elements were visited.
* <p>
* Can be used to check all array elements for nullness.
*
* [code]
* public void foo(final Integer[] values) {
* arrays.forEach(values, new Validator.NonNull());
* ...
* }
* [/code]
*
* @param <T> the array element type
* @param <R> the returned type of the applied function
* @param array the array to iterate.
* @param f the function to apply to every element.
* @throws NullPointerException if one of the elements are {@code null}.
*/
public static <T, R> void forEach(
final T[] array,
final Function<? super T, ? extends R> f
) {
requireNonNull(array, "Array");
requireNonNull(f, "Predicate");
for (int i = 0; i < array.length; ++i) {
f.apply(array[i]);
}
}
/**
* Iterates over all elements of the given {@code values}
*
* @param <T> the element type
* @param <R> the returned type of the applied function
* @param values the values to iterate.
* @param f the function to apply to each element.
* @throws NullPointerException if one of the elements are {@code null}.
*/
public static <T, R> void forEach(
final Iterable<? extends T> values,
final Function<? super T, ? extends R> f
) {
requireNonNull(values, "Array");
requireNonNull(f, "Function");
for (final T value : values) {
f.apply(value);
}
}
/**
* Map the array from type A to an other array of type B.
*
* @param <A> the source type.
* @param <B> the target type.
* @param a the source array.
* @param b the target array. If the given array is to short a new array
* with the right size is created, mapped and returned. If the given
* array is long enough <i>this</i> array is returned.
* @param converter the converter needed for mapping from type A to type B.
* @return the mapped array. If {@code b} is long enough {@code b} is
* returned otherwise a new created array.
* @throws NullPointerException if one of the arguments is {@code null}.
*/
public static <A, B> B[] map(
final A[] a,
final B[] b,
final Function<? super A, ? extends B> converter
) {
requireNonNull(a, "Source array");
requireNonNull(b, "Target array");
requireNonNull(converter, "Converter");
B[] result = b;
if (b.length < a.length) {
@SuppressWarnings("unchecked")
final B[] r = (B[])java.lang.reflect.Array.newInstance(
b.getClass().getComponentType(), a.length
);
result = r;
}
for (int i = 0; i < result.length; ++i) {
result[i] = converter.apply(a[i]);
}
return result;
}
}