All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sri.ai.util.Util Maven / Gradle / Ivy

There is a newer version: 1.3.3
Show newest version
/*
 * Copyright (c) 2013, SRI International
 * All rights reserved.
 * Licensed under the The BSD 3-Clause License;
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 * 
 * http://opensource.org/licenses/BSD-3-Clause
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * 
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * 
 * Neither the name of the aic-util nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.sri.ai.util;

import static com.sri.ai.util.base.PairOf.makePairOf;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.Reader;
import java.io.StringWriter;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Optional;
import java.util.Random;
import java.util.Set;
import java.util.Stack;
import java.util.StringJoiner;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collector;
import java.util.stream.Collectors;

import com.google.common.annotations.Beta;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.sri.ai.util.base.BinaryFunction;
import com.sri.ai.util.base.BinaryPredicate;
import com.sri.ai.util.base.Equals;
import com.sri.ai.util.base.NullaryFunction;
import com.sri.ai.util.base.Pair;
import com.sri.ai.util.base.PairOf;
import com.sri.ai.util.base.TernaryFunction;
import com.sri.ai.util.collect.EZIterator;
import com.sri.ai.util.math.Rational;

/**
 * A suite of general purpose utility routines related to handling errors,
 * string manipulation, I/O, collections, and math that have proven useful over
 * time.
 * 
 * @author braz
 * 
 */
@Beta
public class Util {

	/**
	 * Logs the error message and stack trace for the given exception, and exits
	 * the program, returning code 1.
	 * 
	 * @param e
	 *            the throwable causing the fatal error.
	 */
	public static void fatalError(Throwable e) {
		fatalError(e, true);
	}

	/**
	 * Logs a top level message, the error message and stack trace for the given
	 * exception, and exits the program, returning code 1.
	 * 
	 * @param topLevelMessage
	 *            the top level message describing the fatal error.
	 * @param e
	 *            the throwable causing the fatal error.
	 */
	public static void fatalError(String topLevelMessage, Throwable e) {
		fatalError(topLevelMessage, e, true);
	}

	/**
	 * Logs the error message for the given exception, and optionally logs a
	 * stack trace. Then exits the program with return code 1.
	 * 
	 * @param e
	 *            the throwable causing the fatal error.
	 * @param trace
	 *            indicates whether or not to log the stack trace.
	 */
	public static void fatalError(Throwable e, boolean trace) {
		fatalError("Fatal error: ", e, trace);
	}

	/**
	 * Logs error message and exits.
	 * 
	 * @param msg
	 *            the error message
	 * 
	 */
	public static void fatalError(String msg) {
		fatalError(msg, true);
	}

	/**
	 * Logs error message without loging stack trace, and exits.
	 * 
	 * @param msg
	 *            the error message
	 */
	public static void fatalErrorWithoutStack(String msg) {
		fatalError(msg, false);
	}

	/**
	 * Logs a top level message, the error message for the given exception, and
	 * optionally logs a stack trace. Then exits the program with return code 1.
	 * 
	 * @param topLevelMessage
	 *            the top level message describing the fatal error.
	 * @param e
	 *            the throwable causing the fatal error.
	 * @param trace
	 *            indicates whether or not to log the stack trace.
	 */
	public static void fatalError(String topLevelMessage, Throwable e,
			boolean trace) {
		if (trace) {
			if (e.getCause() != null) {
				System.err.println(topLevelMessage + "\n" + e.getMessage()
						+ "\n" + join("\n", e.getStackTrace()) + "\n"
						+ e.getCause().getMessage() + "\n"
						+ join("\n", e.getCause().getStackTrace()));
			} else {
				System.err.println(topLevelMessage + "\n" + e.getMessage());
			}
		} else {
			System.err.println(topLevelMessage + "\n" + e.getMessage());
		}
		if (e != null) {
			e.printStackTrace();
		}
		System.exit(1);
	}

	/**
	 * Logs error message, optionally logs stack trace, and exits.
	 * 
	 * @param msg
	 *            the error message
	 * 
	 * @param trace
	 *            if true, log a stack trace
	 */
	public static void fatalError(String msg, boolean trace) {
		if (trace) {
			System.err.println(msg + "\n"
					+ join("\n", Thread.currentThread().getStackTrace()));
		} else {
			System.err.println(msg);
		}
		System.exit(1);
	}

	/**
	 * Returns a string with the entire context of an input stream.
	 * 
	 * @param inputStream
	 *            the input stream from which to read all from.
	 * @return a String representation of the entire contents of the given input
	 *         stream.
	 */
	public static String readAll(InputStream inputStream) {
		StringBuilder result = new StringBuilder();
		String line;
		boolean first = true;
		try {
			BufferedReader reader = new BufferedReader(new InputStreamReader(
					inputStream));
			while ((line = reader.readLine()) != null) {
				if (!first) {
					result.append("\n");
				}
				result.append(line);
				first = false;
			}
			return result.toString();
		} catch (Exception e) {
			Util.fatalError("Could not read " + inputStream, e);
		}
		return null;
	}
	
	/**
	 * Returns a string with the entire contents of an input reader.
	 * 
	 * @param inputReader
	 *        the input reader to be read from.
	 * @return all of the contents read from the input reader.
	 * @throws IOException if an error occurs.
	 */
	public static String readAll(Reader inputReader) throws IOException {
		StringWriter result = new StringWriter();
		char[] cbuf = new char[1024];
		int read = 0;
		while ((read = inputReader.read(cbuf)) != -1) {
			result.write(cbuf, 0, read);
		}
		
		return result.toString();
	}

	/**
	 * Returns the string formed by concatenating the two given strings, with a
	 * space in between if both strings are non-empty.
	 * 
	 * @param str1
	 *            the first string to join.
	 * @param str2
	 *            the second string to join.
	 * @return a concatenated version of str1 and str2 with a space in between.
	 */
	public static String join(String str1, String str2) {
		if (str1.length() == 0) {
			return str2;
		}
		if (str2.length() == 0) {
			return str1;
		}

		StringJoiner sj = new StringJoiner(" ");
		sj.add(str1).add(str2);

		return sj.toString();
	}

	/**
	 * Returns a string formed by the concatenation of string versions of the
	 * elements in a collection, separated by a given separator.
	 * 
	 * @param separator
	 *            the separator to use between elements when creating the joined
	 *            string.
	 * @param c
	 *            the collection whose elements toString() values are to be
	 *            joined together.
	 * @return a String constructed from the toString of each element of the
	 *         given collection with the given separator between each argument.
	 */
	public static String join(String separator, Collection c) {
		Iterator it = c.iterator();
		return join(separator, it);
	}

	/**
	 * Returns a string formed by the concatenation of string versions of the
	 * elements in an iterator's range, separated by a given separator.
	 * 
	 * @param separator
	 *            the separator to use between elements when creating the joined
	 *            string.
	 * @param it
	 *            the iterator whose elements toString() values are to be joined
	 *            together.
	 * @return a String constructed from the toString of each element of the
	 *         given iterator with the given separator between each argument.
	 */
	@SuppressWarnings("unchecked")
	public static String join(String separator, Iterator it) {
		StringJoiner sj = new StringJoiner(separator);
		it.forEachRemaining(e -> sj.add(e == null? "null" : e.toString()));
		return sj.toString();
	}

	/**
	 * Same as {@link #join(String, Iterator)}, with ", " for a
	 * separator.
	 * 
	 * @param it
	 *            the iterator whose elements toString() values are to be joined
	 *            together.
	 * @return a String constructed from the toString of each element of the
	 *         given iterator with a comma (", ") separator between
	 *         each argument.
	 */
	public static String join(Iterator it) {
		return join(", ", it);
	}

	/**
	 * Same as {@link #join(String, Collection)}.
	 *
	 * @param c
	 *            the collection whose elements toString() values are to be
	 *            joined together.
	 * @param separator
	 *            the separator to use between elements when creating the joined
	 *            string.
	 * @return a String constructed from the toString of each element of the
	 *         given collection with the given separator between each argument.
	 */
	public static String join(Collection c, String separator) {
		return join(separator, c);
	}

	/**
	 * Calls {@link #join(String, Collection)} with ", " as separator.
	 * 
	 * @param c
	 *            the collection whose elements toString() values are to be
	 *            joined together.
	 * @return a String constructed from the toString of each element of the
	 *         given collection with a comma (", ") separator
	 *         between each argument.
	 */
	public static String join(Collection c) {
		return join(", ", c);
	}

	/**
	 * Calls {@link #join(Collection)} on the given array as a collection.
	 * 
	 * @param a
	 *            the array whose elements toString() values are to be joined
	 *            together.
	 * @return a String constructed from the toString of each element of the
	 *         given array with a comma (", ") separator between
	 *         each argument.
	 */
	public static String join(Object[] a) {
		return join(Arrays.asList(a));
	}

	/**
	 * Calls {@link #join(String, Collection)} on the given array as a
	 * collection.
	 * 
	 * @param separator
	 *            the separator to use between elements when creating the joined
	 *            string.
	 * @param a
	 *            the array whose elements toString() values are to be joined
	 *            together.
	 * @return a String constructed from the toString of each element of the
	 *         given array with the given separator between each argument.
	 */
	public static String join(String separator, Object[] a) {
		return join(separator, Arrays.asList(a));
	}

	/**
	 * Produces a string with map entry representations separated by a given
	 * entry separator, where entry representations are the key and value
	 * representations separated by a key-value separator.
	 * 
	 * @param entrySeparator
	 *            the separator to use between each map entry in the join
	 *            output.
	 * @param keyValueSeparator
	 *            the separator to use between each entry's key value pair in
	 *            the join output.
	 * @param map
	 *            the map whose key value pairs are to be joined into a String.
	 * @return a joined string with an entrySeparator between each entry in the
	 *         given map, each of which has a keyValueSeparator between the
	 *         entry's key and value.
	 */
	public static String join(String entrySeparator, String keyValueSeparator,
			Map map) {
		List c = new LinkedList();
		for (Map.Entry entry : map
				.entrySet()) {
			c.add(entry.getKey() + keyValueSeparator + entry.getValue());
		}
		return join(entrySeparator, c);
	}

	/**
	 * Same as {@link #join(String, String, Map)} with key-value separator equal
	 * to -> .
	 * 
	 * @param entrySeparator
	 *            the separator to use between each map entry in the join
	 *            output.
	 * @param map
	 *            the map whose key value pairs are to be joined into a String.
	 * @return a joined string with an entrySeparator between each entry in the
	 *         given map, each of which has an arrow -> separator between the
	 *         entry's key and value.
	 */
	public static String join(String entrySeparator,
			Map map) {
		return join(entrySeparator, " -> ", map);
	}

	/**
	 * Same as {@link #join(String, String, Map)} with entry separator equal to
	 * ", " and key-value separator equal to ->.
	 * 
	 * @param map
	 *            the map whose key value pairs are to be joined into a String.
	 * @return a joined string with a ", " comma separator between
	 *         each entry in the given map, each of which has an arrow ->
	 *         separator between the entry's key and value.
	 */
	public static String join(Map map) {
		return join(", ", " -> ", map);
	}

	public static List split(String separator, String string) {
		if (separator.length() == 0) {
			throw new Error("Util.split cannot run on empty separator.");
		}

		List result = new LinkedList();
		int begin = 0;
		int end;

		while (begin <= string.length()) {
			end = string.indexOf(separator, begin);
			if (end == -1) {
				end = string.length();
			}
			result.add(string.substring(begin, end));
			begin = end + separator.length();
		}

		return result;
	}

	/**
	 * Construct an Object array of the given elements.
	 * 
	 * @param elements
	 *            the elements to construct an array from.
	 * @return the received arguments in an array.
	 * 
	 */
	public static Object[] array(Object... elements) {
		return elements;
	}

	/**
	 * Construct a list of the given type populated with the provided elements.
	 * 
	 * @param elements
	 *            the elements to construct the List from.
	 * @return the received arguments in a linked list.
	 * @param 
	 *            the type of the elements in the list.
	 */
	@SafeVarargs
	public static  List list(T... elements) {
		return new LinkedList(Arrays.asList(elements));
	}

	/**
	 * Construct an iterator of the given type ranging over provided elements.
	 * 
	 * @param elements
	 *            the elements to construct the List from.
	 * @return an iterator over the received arguments.
	 * @param 
	 *            the type of elements the iterator will range over.
	 */
	public static  Iterator iterator(T... elements) {
		return Arrays.asList(elements).iterator();
	}

	/**
	 * Construct an {@link ArrayList} of the given type populated with the provided elements.
	 * 
	 * @param elements
	 *            the elements to construct the List from.
	 * @return the received arguments in an array list.
	 * @param 
	 *            the type of the List to be constructed and the elements it is
	 *            to contain.
	 */
	@SafeVarargs
	public static  ArrayList arrayList(T... elements) {
		return new ArrayList(Arrays.asList(elements));
	}

	/**
	 * @return an empty stack of the given type.
	 * @param 
	 *            the type of the Stack to instantiate.
	 */
	public static  Stack stack() {
		Stack result = new Stack();
		return result;
	}

	public static  Set set(T... elements) {
		return new LinkedHashSet(Arrays.asList(elements));
	}

	@SuppressWarnings("unchecked")
	public static  List singletonListIfNotNullOrEmptyListIfNull(T element) {
		if (element == null) {
			return new LinkedList();
		}
		else {
			return list(element);
		}
	}
	
	public static boolean isEven(int number) {
		return number % 2 == 0;
	}

	/**
	 * 
	 * @param keysAndValues
	 *            a sequence of key and value pairs to be placed into a new Map.
	 * 
	 * @return the received arguments (interpreted as a sequence of key and
	 *         value pairs) in a hash map.
	 * @param 
	 *            the type of the Map's key.
	 * @param 
	 *            the type of the Map's value.
	 */
	public static  LinkedHashMap map(Object... keysAndValues) {
		if (!isEven(keysAndValues.length)) {
			fatalError("Util.map(Object ...) must receive an even number of arguments but received "
					+ keysAndValues.length
					+ ": "
					+ join(";", keysAndValues)
					+ ".");
		}
		LinkedHashMap result = new LinkedHashMap();
		putAll(result, keysAndValues);
		return result;
	}

	/**
	 * @param map
	 *        a map.
	 * @param keysAndValues
	 *            a sequence of key and value pairs to be placed into a given Map.
	 * 
	 * @return the received arguments (interpreted as a sequence of key and
	 *         value pairs) in a given map.
	 * @param 
	 *            the type of the Map's key.
	 * @param 
	 *            the type of the Map's value.
	 */
	@SuppressWarnings("unchecked")
	public static  Map putAll(Map map, Object... keysAndValues) {
		int i = 0;
		while (i != keysAndValues.length) {
			map.put((K) keysAndValues[i], (V) keysAndValues[i + 1]);
			i += 2;
		}
		return map;
	}

	/**
	 * Add given element of a given collection to a collection value in a map,
	 * creating it in advance (as an instance of given class) if needed.
	 * 
	 * @param mapToCollections
	 *            the map containing the collections to be added to.
	 * @param key
	 *            the key identifying the collection in the given map to be
	 *            added to.
	 * @param element
	 *            the element to be added to the identified collection.
	 * @param newCollectionClass
	 *            the class of the collection to create if it is not currently
	 *            mapped to in the given map.
	 * @param 
	 *            the type of the Map's key.
	 * @param 
	 *            the type of the Map's value.
	 */
	@SuppressWarnings("unchecked")
	public static  void addToCollectionValuePossiblyCreatingIt(
			Map> mapToCollections, K key, V element,
			Class newCollectionClass) {
		Collection c = mapToCollections.get(key);
		if (c == null) {
			try {
				c = (Collection) newCollectionClass.newInstance();
				mapToCollections.put(key, c);
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}
		c.add(element);
	}

	/**
	 * Add all elements of a given collection to a collection value in a map,
	 * creating it in advance (as an instance of given class) if needed.
	 * 
	 * @param mapToCollections
	 *            the map containing the collections to be added to.
	 * @param key
	 *            the key identifying the collection in the given map to be
	 *            added to.
	 * @param elements
	 *            the elements to be added to the identified collection.
	 * @param newCollectionClass
	 *            the class of the collection to create if it is not currently
	 *            mapped to in the given map.
	 */
	@SuppressWarnings("unchecked")
	public static void addAllToCollectionValuePossiblyCreatingIt(
			Map mapToCollections, Object key, Collection elements,
			Class newCollectionClass) {
		Collection c = (Collection) mapToCollections.get(key);
		if (c == null) {
			try {
				c = (Collection) newCollectionClass.newInstance();
				mapToCollections.put(key, c);
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}
		c.addAll(elements);
	}

	/**
	 * Given two maps of collections, add all elements in each collection2 of second map
	 * to the corresponding (that is, associated with the same key) collection1 in first map,
	 * guaranteeing to keep collection2's instance if collection1 is absent or empty,
	 * and returns the first map, unless it is null, in which case the second map is returned.
	 *
	 * @param map1
	 *        map 1
	 * @param map2
	 *        map 2
	 * @return the first map, unless it is null, in which case the second map is returned
	 * @param  a map type
	 * @param  a value type
	 * @param  a key type
	 */
	public static >, K, V> M addAllForEachEntry(M map1, M map2) {
		M result;
		if (map1 == null) {
			result = map2;
		}
		else {
			for (Map.Entry> entry : map2.entrySet()) {
				Collection collectionInMap1 = map1.get(entry.getKey());
				Collection collectionInMap2 = entry.getValue();
				Collection entryUnion = addAllOrSame(collectionInMap1, collectionInMap2);
				if (entryUnion != collectionInMap1) {
					map1.put(entry.getKey(), entryUnion);
				}
			}
			result = map1;
		}
		return result;
	}

	/**
	 * Adds to a collection all given new elements in a second collection, returning the second collection
	 * same instance if the first is null or empty.
	 * @param collection
	 *        a collection
	 * @param newElements
	 *        new elements
	 * @return if collection null then newElements, else collection with newElements added to it.
	 * @param  the type of the elements in the collection.
	 */
	public static  Collection addAllOrSame(Collection collection, Collection newElements) {
		Collection result;
		if (collection == null || collection.isEmpty()) {
			result = newElements;
		}
		else {
			collection.addAll(newElements);
			result = collection;
		}
		return result;
	}

	/**
	 * Given a map, a function on its entries, and a value combination function,
	 * returns a pair of:
	 * 
    *
  • a new map containing the transformed entries; * if multiple entries have their keys transformed to the same new key, * their values will be combined with the value combination function. *
  • a set of keys of the original entries that were transformed; * an entry is considered transformed if the returned pair is not null, * and if either its key or value identities (instances) have changed *
* The function receives an entry from the original map as its input and returns * a {@link Pair} with new key and new value as output. * * @param map * a map * @param function * a function * @param valueCombination * a value combination * @return a pair with values as described in description. * @param type of key 1 * @param type of value 1 * @param type of key 2 * @param type of value 2 */ public static Pair, Set> getTransformedSubMapAndOriginalKeysOfTransformedEntries( Map map, Function, Pair> function, BinaryFunction valueCombination) { Map transformedSubMap = new LinkedHashMap(); Set originalKeysOfTransformedEntries = new LinkedHashSet(); for (Map.Entry entry : map.entrySet()) { Pair transformedEntry = function.apply(entry); if (transformedEntry != null && (transformedEntry.first != entry.getKey() || transformedEntry.second != entry.getValue())) { V2 newValue = transformedEntry.second; V2 alreadyPresentValueForNewKey = transformedSubMap.get(transformedEntry.first); if (alreadyPresentValueForNewKey == null) { newValue = transformedEntry.second; } else { newValue = valueCombination.apply(alreadyPresentValueForNewKey, transformedEntry.second); } transformedSubMap.put(transformedEntry.first, newValue); originalKeysOfTransformedEntries.add(entry.getKey()); } } return Pair.make(transformedSubMap, originalKeysOfTransformedEntries); } /** * Adds all elements of iterator's range to collection. * * @param c * the collection to add the iterator's range to. * @param i * the iterator whose range is to be added to the given * collection. * @return the given collection. * @param * the type of the elements given. * @param the type of the collection */ public static > C addAll(C c, Iterator i) { while (i.hasNext()) { c.add(i.next()); } return c; } /** * Adds all elements of iterator's range to a new linked list. * * @param i * the iterator whose range is to be added to the list. * @return the list. * @param * the type of the elements given. */ public static LinkedList addAllToList(Iterator i) { LinkedList result = new LinkedList(); while (i.hasNext()) { result.add(i.next()); } return result; } /** * Adds all elements of iterator's range to a new linked hash set. * * @param i * the iterator whose range is to be added to the set. * @return the set. * @param * the type of the elements given. */ public static LinkedHashSet addAllToSet(Iterator i) { LinkedHashSet result = new LinkedHashSet(); while (i.hasNext()) { result.add(i.next()); } return result; } /** * @param map * the map to look up a value using the given key. * @param key * the key to look up the given map with. * @param defaultValue * the defaultValue to return if the given key is not in the map. * @return value indexed by given key in map, or a default value if that is * null. * @param * the type of the Map's key. * @param * the type of the Map's value. */ public static V getOrUseDefault(Map map, K key, V defaultValue) { V result = map.get(key); if (result == null) { result = defaultValue; } return result; } @SuppressWarnings("unchecked") public static V getValuePossiblyCreatingIt(Map map, K key, Class newValueClass) { V value = map.get(key); if (value == null) { try { value = (V) newValueClass.newInstance(); } catch (InstantiationException e) { e.printStackTrace(); System.exit(-1); } catch (IllegalAccessException e) { e.printStackTrace(); System.exit(-1); } map.put(key, value); } return value; } public static V getValuePossiblyCreatingIt(Map map, K key, Function makerFromKey) { V value = map.get(key); if (value == null) { value = makerFromKey.apply(key); map.put(key, value); } return value; } public static File createTempFileWithContent(String content, String pattern, String suffix) { File temp = null; try { // Create temp file. temp = File.createTempFile(pattern, "." + suffix); // Delete temp file when program exits. temp.deleteOnExit(); // Write to temp file BufferedWriter out = new BufferedWriter(new FileWriter(temp)); out.write(content); out.close(); } catch (IOException e) { Util.fatalError("Could not create temporary file."); } return temp; } public static boolean isEmpty(Iterable i) { return !i.iterator().hasNext(); } /** * * @param element * the element to test. * @param iterable * An iterable object. * @param predicate * the predicate to test if the given element has found a match * in the iterable object. * @return an Iterator that has just iterated past an element x * of iterable such that * predicate.evaluate(element, x) is true, or * null if there is no such element. * @param * the type of the element to find. */ public static Iterator find(E element, Iterable iterable, BinaryPredicate predicate) { Iterator i = iterable.iterator(); boolean foundIt = false; while (i.hasNext() && !(foundIt = predicate.apply(element, i.next()))) { ; } if (foundIt) { return i; } return null; } public static boolean removeAnyTwoMatchingElements(Iterable a, Iterable b, BinaryPredicate predicate) { Iterator aI = a.iterator(); Iterator bI = null; while (aI.hasNext() && (bI = find(aI.next(), b, predicate)) != null) { ; } if (bI != null) { aI.remove(); bI.remove(); return true; } return false; } /** * If there is no element in collection satisfying given predicate, returns * null. Otherwise, returns list with elements in iteration order, excluding * the first satisfying element. * * @param c * the collection to copy elements from. * @param p * the predicate to test elements on the given collection for * whether or not they should be copied or not. * @return null if no element in given collection satisfying given * predicate, otherwise a list with elements in iteration order, * excluding the first element satisfying the predicate. * @param * the type of the elements in the collection. */ public static List listCopyWithoutSatisfyingElementOrNull( Collection c, Predicate p) { Pair> satisfyingElementAndListCopyWithoutIt = findSatisfyingElementAndListCopyWithoutItOrNull( c, p); return satisfyingElementAndListCopyWithoutIt.second; } /** * If there is no element in collection satisfying given predicate, returns * null. Otherwise, returns pair with found element and a list with elements * in iteration order, excluding the first satisfying element. * * @param c * the collection to copy elements from. * @param p * the predicate to test elements on the given collection for * whether or not they should be copied or not. * @return null if no element in given collection satisfying given * predicate, otherwise a pair with found element and a list with * elements in iteration order, excluding the first satisfying * element. * @param * the type of the elements in the collection. */ public static Pair> findSatisfyingElementAndListCopyWithoutItOrNull( Collection c, Predicate p) { Pair> result = null; final AtomicInteger elementIndex = new AtomicInteger(-1); Optional first = c.stream().filter(e -> { elementIndex.incrementAndGet(); return p.apply(e); }).findFirst(); if (first.isPresent()) { // we create another list and add all elements, but found one, to // it. List copy = makeCopyButForElementAtGivenIndex(c, elementIndex.intValue()); result = Pair.make(first.get(), copy); } return result; } /** * Given a collection and an index, returns a list with the collection's * elements in iteration order, excluding the elementIndex-th element. * * @param c * the collection whose elements are to be copied. * @param elementIndex * the index of the element to be excluded from the copied * collection. * @return a list wit the collection's elements in iteration order, * excluding the elementIndex-th element. * @param * the type of the elements in the collection. */ public static List makeCopyButForElementAtGivenIndex( Collection c, int elementIndex) { final AtomicInteger currentIndex = new AtomicInteger(-1); List result = c.stream() .filter(e -> currentIndex.incrementAndGet() != elementIndex) .collect(toLinkedList()); return result; } /** * Stores iterator's range in a new, empty list and returns it. * * @param iterator * the iterator whose range is to be stored in a new List. * @return a new List populated with the elements from the given iterator's * range. * @param * the type of the elements iterated over. */ public static List listFrom(Iterator iterator) { LinkedList result = new LinkedList(); while (iterator.hasNext()) { result.add(iterator.next()); } return result; } /** * Stores iterator's range in a new, empty array list and returns it. * * @param iterator * the iterator whose range is to be stored in a new ArrayList. * @return a new ArrayList populated with the elements from the given iterator's * range. * @param * the type of the elements iterated over. */ public static ArrayList arrayListFrom(Iterator iterator) { ArrayList result = new ArrayList(); while (iterator.hasNext()) { result.add(iterator.next()); } return result; } /** * Makes a list out of an array. * * @param array * the array from which to construct a list. * @return a List containing the elements of the given array. * @param * the type of the array's elements. */ public static List listFrom(T[] array) { LinkedList result = new LinkedList(); for (int i = 0; i != array.length; i++) { result.add(array[i]); } return result; } /** * Stores results of applying a function to an iterator's range in a given list. * * @param iterator * the iterator's whose range a function is to be applied to. * @param function * the function to be applied to the given iterator's range. * @param result a list to which we add the results from the function applications on the given * iterator's range. * @param * the type of the iterators arguments. * @param * the result type of the function applied to the iterator's * range. */ protected static void mapIntoList(Iterator iterator, Function function, List result) { while (iterator.hasNext()) { F nextElement = iterator.next(); result.add(function.apply(nextElement)); } } /** * Stores results of applying a function to the elements of a collection in a given list. * * @param collection * the collection to whose elements a function is to be applied to. * @param function * the function to be applied to the given iterator's range. * @param result a list to which we add the results from the function applications on the given * collection elements. * @param * the type of the collection elements. * @param * the result type of the function applied to the collection elements. */ public static void mapIntoList(Collection collection, Function function, List result) { mapIntoList(collection.iterator(), function, result); } /** * Stores results of applying a function to an iterator's range in a new, * empty list and returns it. * * @param iterator * the iterator's whose range a function is to be applied to. * @param function * the function to be applied to the given iterator's range. * @return a List of the results from the function applications on the given * iterator's range. * @param * the type of the iterators arguments. * @param * the result type of the function applied to the iterator's * range. */ public static List mapIntoList(Iterator iterator, Function function) { List result = new LinkedList(); mapIntoList(iterator, function, result); return result; } /** * Stores results of applying a function to a collection's elements in a * new, empty list and returns it. * * @param collection * the collection whose elements a function is to be applied to. * @param function * the function to be applied to the given collection's elements. * @return a List of the results from the function applications on the given * collection's elements. * @param * the type of the collection's elements. * @param * the result type of the function applied to the collection's * elements. */ public static List mapIntoList( Collection collection, Function function) { return mapIntoList(collection.iterator(), function); } /** * Stores results of applying a function to a collection's elements in a * new, empty array list and returns it. * * @param collection * the collection whose elements a function is to be applied to. * @param function * the function to be applied to the given collection's elements. * @return an ArrayList of the results from the function applications on the * given collection's elements. * @param * the type of the collection's elements. * @param * the result type of the function applied to the collection's * elements. */ public static ArrayList mapIntoArrayList( Collection collection, Function function) { ArrayList result = collection .stream() .map(function::apply) .collect(toArrayList(collection.size())); // ArrayList result = new ArrayList(collection.size()); // for (F element : collection) { // result.add(function.apply(element)); // } return result; } /** * Stores results of applying a function to iterator's range in a * new, empty array list and returns it. * * @param iterator * the iterator whose range's elements a function is to be applied to. * @param function * the function to be applied to the given iterator's range elements. * @return an ArrayList of the results from the function applications on the * given iterator's range elements. * @param * the type of the iterator's range elements. * @param * the result type of the function applied to the iterator's range elements. */ public static ArrayList mapIntoArrayList( Iterator iterator, Function function) { ArrayList result = new ArrayList(); for (F element : in(iterator)) { result.add(function.apply(element)); } return result; } /** * Stores results of applying a function to an array's elements in a * new, empty array list and returns it. * * @param array * the array whose elements a function is to be applied to. * @param function * the function to be applied to the given collection's elements. * @return an ArrayList of the results from the function applications on the * given collection's elements. * @param * the type of the collection's elements. * @param * the result type of the function applied to the collection's * elements. */ public static ArrayList mapIntoArrayList(F[] array, Function function) { ArrayList result = Arrays .stream(array) .map(function::apply) .collect(toArrayList(array.length)); return result; } public static List mapIntoList(F[] array, Function function) { return mapIntoList(Arrays.asList(array), function); } /** * Stores results of applying a function to a collection's elements in a * new array and returns it. * * @param clazz the type of the objects in the array * @param collection * the collection whose elements a function is to be applied to. * @param function * the function to be applied to the given collection's elements. * @return an array of the results from the function applications on the * given collection's elements. * @param * the type of the collection's elements. * @param * the result type of the function applied to the collection's * elements. */ public static T[] mapIntoArray(Class clazz, Collection collection, Function function) { @SuppressWarnings("unchecked") T[] result = (T[]) Array.newInstance(clazz, collection.size()); int i = 0; for(F element : collection) { result[i++] = function.apply(element); } return result; } /** * Stores results of applying a function to a collection's elements in a * new array of Objects and returns it. * * @param collection * the collection whose elements a function is to be applied to. * @param function * the function to be applied to the given collection's elements. * @return an array of the results from the function applications on the * given collection's elements. * @param * the type of the collection's elements. * @param * the result type of the function applied to the collection's * elements. */ public static T[] mapIntoObjectArray(Collection collection, Function function) { @SuppressWarnings("unchecked") T[] result = (T[]) new Object[collection.size()]; int i = 0; for(F element : collection) { result[i++] = function.apply(element); } return result; } /** * Indicates whether two collections contain the exact same instances in the * same (iterable) order. * * @param c1 * the first collection to test. * @param c2 * the second collection to test. * @return true if the two collections contain the eact same instances in * the same (iterable) order, false otherwise. * @param * the type of the elements in the given collections. */ public static boolean sameInstancesInSameIterableOrder( Collection c1, Collection c2) { Iterator i1 = c1.iterator(); Iterator i2 = c2.iterator(); while (i1.hasNext() && i2.hasNext()) { if (i1.next() != i2.next()) { return false; } } boolean result = !i1.hasNext() && !i2.hasNext(); // only true if they // are both done at // the same time return result; } /** * Stores results of applying a function to an set's elements in a new, * empty hash set and returns it. * * @param set * the set to map from. * @param function * the function to apply to each element in the set. * @return the results of applying the given function to the elements of the * given set. * @param * the type of the elements in the Set. * @param * the type of the result from applying the given function. */ public static Set mapIntoSet(Collection set, Function function) { Set result = set .stream() .map(function::apply) .collect(toLinkedHashSet(set.size())); return result; } /** * Stores results of applying a function to an collection's elements in a new, * empty linked hash set and returns it if any elements are distinct instances from originals, * or original collection otherwise. * * @param set * the set to map from. * @param function * the function to apply to each element in the set. * @return the results of applying the given function to the elements of the * given set, or same set if there are no changes * @param * the type of the result from applying the given function. */ public static Collection mapIntoSetOrSameIfNoDistinctElementInstances(Collection set, Function function) { Collection possibleResult = new LinkedHashSet(); boolean change = false; for (T element : set) { T elementResult = function.apply(element); possibleResult.add(elementResult); change = change || elementResult != element; } return change? possibleResult : set; } /** * Collects elements in an iterator's range satisfying two different * conditions, returning false if some element does not satisfy either. * * @param iterator * an iterator over a collection of elements to be tested. * @param satisfyingCondition1 * populated with elements that satisfy condition1. * @param condition1 * the test to be applied to the iterator's range to be passed in * order to add elements to the given satisfyingCondition1 * collection. * @param satisfyingCondition2 * populated with elements that satisfy condition2. * @param condition2 * the test to be applied to the iterator's range to be passed in * order to add elements to the given satisfyingCondition2 * collection. * @return false is some element in the given iterator's range does not * satisfy both given conditions, true otherwise. * @param * the type of the elements in the given collections. */ public static boolean collectOrReturnFalseIfElementDoesNotFitEither( Iterator iterator, Collection satisfyingCondition1, Predicate condition1, Collection satisfyingCondition2, Predicate condition2) { while (iterator.hasNext()) { E object = iterator.next(); boolean result1; boolean result2; if (result1 = condition1.apply(object)) { satisfyingCondition1.add(object); } if (result2 = condition2.apply(object)) { satisfyingCondition2.add(object); } if (!result1 && !result2) { return false; } } return true; } /** * Collects elements in a collection satisfying two different conditions, * returning false if some element does not satisfy either. * * @param collection * a collection of elements to be tested. * @param satisfyingCondition1 * populated with elements that satisfy condition1. * @param condition1 * the test to be applied to the elements of the given collection * to be passed in order to add elements to the given * satisfyingCondition1 collection. * @param satisfyingCondition2 * populated with elements that satisfy condition2. * @param condition2 * the test to be applied to the elements of the given collection * to be passed in order to add elements to the given * satisfyingCondition2 collection. * @return false is some element in the given collection does not satisfy * both given conditions, true otherwise. * @param * the type of the elements in the given collections. */ public static boolean collectOrReturnFalseIfElementDoesNotFitEither( Collection collection, Collection satisfyingCondition1, Predicate condition1, Collection satisfyingCondition2, Predicate condition2) { return collectOrReturnFalseIfElementDoesNotFitEither( collection.iterator(), satisfyingCondition1, condition1, satisfyingCondition2, condition2); } /** * Collects elements in an iterator's range into two different given * collections, one with the N first elements satisfying a condition and the * other with the elements not doing so. Returns the index of the first of * the n elements satisfying condition or -1 if there aren't n element * satisfying the predicate. * * @param iterator * the iterator over whose range the first n are to be collected * from * @param n * the maximum number to be collected. * @param condition * the satisfying condition predicate * @param satisfyingCondition * those elements from the iterator's range that satisfy the * condition. * @param remaining * those elements from the iterator's range that don't satisfy * the condition. * @return the index of the first of the n elements satisfying the * condition, -1 if there aren't n elements satisfying the * condition. * @param * the type of the elements from the iterator's range. */ public static int collectFirstN(Iterator iterator, int n, Predicate condition, Collection satisfyingCondition, Collection remaining) { int i = 0; int result = -1; while (iterator.hasNext()) { E object = iterator.next(); if (n > 0 && condition.apply(object)) { satisfyingCondition.add(object); n--; if (result == -1) { result = i; } } else { remaining.add(object); } i++; } if (n != 0) { return -1; } return result; } /** * Collects elements in a collection into two different given collections, * one with the N first elements satisfying a condition and the other with * the elements not doing so. Returns the index of the first of the n * elements satisfying condition or -1 if there aren't n element satisfying * the predicate. * * @param c * the collection the first n elements are to be collected from. * @param n * the maximum number to be collected. * @param condition * the satisfying condition predicate * @param satisfyingCondition * those elements from the collection that satisfy the condition. * @param remaining * those elements from the collection that don't satisfy the * condition. * @return the index of the first of the n elements satisfying the * condition, -1 if there aren't n elements satisfying the * condition. * @param * the type of the elements from the input collection. */ public static int collectFirstN(Collection c, int n, Predicate condition, Collection satisfyingCondition, Collection remaining) { int result = collectFirstN(c.iterator(), n, condition, satisfyingCondition, remaining); return result; } /** * Collects elements in a given iterable into two different given * collections, one with the elements satisfying a condition and the other * with the elements not doing so. Returns the index of the first element * satisfying condition. * * @param iterable * an iterable over the elements to be tested. * @param satisfyingCondition * elements from the iterable that satisfy the given condition * will be added to this collection. * @param condition * the predicate used to test the elements in the given iterable. * @param remaining * elements from the iterable that do not satisfy the given * condition will be added to this collection. * @return the index of the first element satisfying the condition, -1 if * none satisfy. * @param * the type of the elements being collected. */ public static int collect(Iterable iterable, Collection satisfyingCondition, Predicate condition, Collection remaining) { final AtomicInteger i = new AtomicInteger(0); final AtomicInteger result = new AtomicInteger(-1); iterable.forEach(e -> { if (condition.apply(e)) { satisfyingCondition.add(e); if (result.intValue() == -1) { result.set(i.intValue()); } } else { remaining.add(e); } i.incrementAndGet(); }); return result.intValue(); } /** * Collects elements in a collection satisfying a given predicate into a * given collection, returning the latter. * * @param collection * the collection from which elements are to be collected from. * @param collected * elements from the given collection that pass the given * predicate test will be added to this collection. * @param predicate * the test to be used to select collect elements from the given * collection. * @return collected. * @param * the type of the elements being collected. */ public static Collection collect(Collection collection, Collection collected, Predicate predicate) { collection.stream().filter(predicate::apply) .forEach(collected::add); return collected; } /** * Collects elements in an iterator's range satisfying a given predicate * into a given collection, returning the latter. * * @param iterator * an iterator over whose range elements are to be collected * from. * @param collected * elements from the given iterator's range that pass the given * predicate test will be added to this collection. * @param predicate * the test to be used to select iterated elements from the given * iterator. * @return collected. * @param * the type of the elements being collected. */ public static Collection collect(Iterator iterator, Collection collected, Predicate predicate) { iterator.forEachRemaining(e -> { if (predicate.apply(e)) { collected.add(e); } }); return collected; } /** * Collects elements in a collection satisfying a given predicate into a new * linked list and returns it. * * @param collection * the collection from which elements are to be copied. * @param predicate * the test to be applied to determine which elements should be * copied into the returned list. * @return a List of the elements in the collection that matched the given * predicate. * @param * the type of the elements to collect. */ public static List collectToList(Collection collection, Predicate predicate) { return (List) collect(collection, new LinkedList(), predicate); } /** * Collects elements in an iterator's range satisfying a given predicate into a new * linked list and returns it. * * @param iterator * the iterator from which elements are to be copied. * @param predicate * the test to be applied to determine which elements should be * copied into the returned list. * @return a List of the elements in the collection that matched the given * predicate. * @param * the type of the elements to collect. */ public static List collectToList(Iterator iterator, Predicate predicate) { return (List) collect(iterator, new LinkedList(), predicate); } /** * Collects elements in a collection satisfying a given predicate into a new * array list and returns it. * * @param collection * the collection from which elements are to be copied. * @param predicate * the test to be applied to determine which elements should be * copied into the returned list. * @return a List of the elements in the collection that matched the given * predicate. * @param * the type of the elements to collect. */ public static ArrayList collectToArrayList(Collection collection, Predicate predicate) { return (ArrayList) collect(collection, new ArrayList(), predicate); } /** * Collects elements in an iterator's range satisfying a given predicate into a new * linked array list and returns it. * * @param iterator * the iterator from which elements are to be copied. * @param predicate * the test to be applied to determine which elements should be * copied into the returned list. * @return a List of the elements in the collection that matched the given * predicate. * @param * the type of the elements to collect. */ public static ArrayList collectToArrayList(Iterator iterator, Predicate predicate) { return (ArrayList) collect(iterator, new ArrayList(), predicate); } /** * Returns a list containing the elements in collection that satisfy the predicate. * @param collection * a collection to filter * @param predicate * a predicate to filter the given collection with. * @return a new list containing the elements in the give collection that satisfy the given predicate. * @param the type of elements in the list */ public static List filter(Collection collection, Predicate predicate) { List result = new LinkedList(); for (T element : collection) { if (predicate.apply(element)) { result.add(element); } } return result; } /** * Returns the number of elements in collection satisfying predicate. * @param collection * a collection to count * @param predicate * a predicate to indicate which elements should be counted. * @return the number of elements in the given collection satisfying the given predicate. * @param * the type of the elements in the collection. */ public static int count(Collection collection, Predicate predicate) { int result = 0; for (T element : collection) { if (predicate.apply(element)) { result++; } } return result; } /** * Returns the number of elements in an iterator's range satisfying predicate. * @param iterator * an iterator whose range to count the elements of * @return the number of elements in the given iterator's range. * @param * the type of the elements in the iterator's range. */ public static int count(Iterator iterator) { int result = 0; while (iterator.hasNext()) { iterator.next(); result++; } return result; } public static Number numberInJustNeededType(double number) { if (Math.floor(number) == number) { return Integer.valueOf((int) number); } return new Double(number); } public static Number sum(Iterator numbersIt) { double sum = 0; while (numbersIt.hasNext()) { sum += numbersIt.next().doubleValue(); } return numberInJustNeededType(sum); } public static Number sum(Collection numbers) { return sum(numbers.iterator()); } /** * Returns the sum of the elements in an array of integers. * @param array an array of ints * @return the sum of the elements in an array of integers. */ public static int sum(int[] array) { int result = 0; for (int element : array) { result += element; } return result; } public static Rational sumArbitraryPrecision(Iterator numbersIt) { Rational sum = Rational.ZERO; while (numbersIt.hasNext()) { Rational number = (Rational) numbersIt.next(); sum = sum.add(number); } return sum; } public static Rational sumArbitraryPrecision(Collection numbers) { return sumArbitraryPrecision(numbers.iterator()); } public static Number product(Iterator numbersIt) { double product = 1; while (numbersIt.hasNext()) { product *= numbersIt.next().doubleValue(); if (product == 0) { break; } } return numberInJustNeededType(product); } public static Number product(Collection numbers) { return product(numbers.iterator()); } public static Rational productArbitraryPrecision(Iterator numbersIt) { Rational product = Rational.ONE; while (numbersIt.hasNext()) { Rational number = (Rational) numbersIt.next(); product = product.multiply(number); if (product.equals(0)) { break; } } return product; } public static Rational productArbitraryPrecision(Collection numbers) { return productArbitraryPrecision(numbers.iterator()); } /** * Returns a Number representing the quotient of a division, or null if * denominator is zero. * * @param numerator * the numerator. * @param denominator * the denominator. * @return a Number representing the quotient of a division, or null if * denominator is zero. */ public static Number division(Number numerator, Number denominator) { double denominatorValue = denominator.doubleValue(); if (denominatorValue == 0) { return null; } double numeratorValue = numerator.doubleValue(); double quotientValue = numeratorValue / denominatorValue; return numberInJustNeededType(quotientValue); } /** * Returns a Number representing the quotient of a division, or null if * denominator is zero, with arbitrary precision when possible. * * @param numerator * the numerator. * @param denominator * the denominator. * @return a Number representing the quotient of a division, or null if * denominator is zero, with arbitrary precision when possible. */ public static Rational divisionWithArbitraryPrecisionIfPossible( Rational numerator, Rational denominator) { if (denominator.isZero()) { return null; } // Note: In the case of Rational as opposed to the previously used // BigDecimal, // this should always be possible. Rational quotient = numerator.divide(denominator); return quotient; } /** * Returns the maximum in collection of numbers, or null if collection is * empty. * * @param numbers * a collection of numbers a maximum is to be found for. * @return the maximum element in the given collection, or null if * collection is empty. */ public static Number max(Collection numbers) { Number result = max( numbers, (Number n1, Number n2) -> Double.compare(n1.doubleValue(), n2.doubleValue())); if (result != null) { result = numberInJustNeededType(result.doubleValue()); } return result; } /** * Returns the minimum in collection of numbers, or null if collection is * empty. * * @param numbers * a collection of numbers a minimum is to be found for. * @return the minimum element in the given collection, or null if * collection is empty. */ public static Number min(Collection numbers) { Number result = min( numbers, (Number n1, Number n2) -> Double.compare(n1.doubleValue(), n2.doubleValue())); if (result != null) { result = numberInJustNeededType(result.doubleValue()); } return result; } /** * Returns the maximum element in a collection according to a comparator. * * @param c * the collection to find a maximum from. * @param comparator * the comparator to use to determine the maximum between * elements. * @return the maximum of the given collection, or null if the collection is * empty. * @param * the type of the elements in the collection. */ public static T max(Collection c, Comparator comparator) { T result = null; Optional max = c.stream().max(comparator); if (max.isPresent()) { result = max.get(); } return result; } /** * Returns the maximum value of given function to an element of collection, * or null if collection is empty. * * @param c * the collection to find a maximum from. * @param function * the function. * @return the maximum value of function on any element of the given collection, * or null if the collection is empty. * @param * the type of the elements in the collection. */ public static Integer max(Collection c, Function function) { Integer result = null; for (T element : c) { Integer value = function.apply(element); if (result == null || value.compareTo(result) > 0) { result = value; } } return result; } /** * Returns the minimum element in a collection according to a comparator. * * @param c * the collection to find a minimum from. * @param comparator * the comparator to use to determine the minimum between * elements. * @return the minimum of the given collection, or null if the collection is * empty. * @param * the type of the elements in the collection. */ public static T min(Collection c, Comparator comparator) { T result = null; Optional min = c.stream().min(comparator); if (min.isPresent()) { result = min.get(); } return result; } /** * Returns the minimum value of given function to an element of collection, * or null if collection is empty. * * @param c * the collection to find a minimum from. * @param function * the function. * @return the minimum value of function on any element of the given collection, * or null if the collection is empty. * @param * the type of the elements in the collection. */ public static Integer min(Collection c, Function function) { Integer result = null; for (T element : c) { Integer value = function.apply(element); if (result == null || value.compareTo(result) < 0) { result = value; } } return result; } /** * Returns the element in a collection whose value for the given function is minimum, * or null if collection is empty. * * @param c * the collection to find an element with a minimum function value. * @param function * the function. * @return the element with a minimum function value, * or null if the collection is empty. * @param * the type of the elements in the collection. */ public static T argmin(Collection c, Function function) { Integer minimum = null; T result = null; for (T element : c) { Integer value = function.apply(element); if (minimum == null || value.compareTo(minimum) < 0) { minimum = value; result = element; } } return result; } /** * Returns the element in a collection whose value for the given function is maximum, * or null if collection is empty. * * @param c * the collection to find an element with a maximum function value. * @param function * the function. * @return the element with a maximum function value, * or null if the collection is empty. * @param * the type of the elements in the collection. */ public static T argmax(Collection c, Function function) { Integer maximum = null; T result = null; for (T element : c) { Integer value = function.apply(element); if (maximum == null || value.compareTo(maximum) < 0) { maximum = value; result = element; } } return result; } public static Boolean and(Iterator booleansIt) { while (booleansIt.hasNext()) { if (!booleansIt.next()) { return false; } } return true; } public static Boolean and(Collection booleans) { return !booleans.stream().filter(b -> !b).findFirst().isPresent(); } public static Boolean or(Collection booleans) { return booleans.stream().filter(b -> b).findFirst().isPresent(); } /** * Returns a list composed of all elements of given list but the first one. * Throws an exception if list is empty. * * @param list * the list all elements except the first are to be returned * from. * @return the input list excluding the first element. * @param * the type of the elements in the list. */ public static List rest(List list) { List result = list.subList(1, list.size()); return result; } public static T applyTillIdentityDoesNotChange(Function function, T object) { T previousOne; do { previousOne = object; object = function.apply(previousOne); } while (object != previousOne); return object; } public static T applyFunctionsFromIteratorUntilFindingDifferentIdentityResultThenReturnIt( Iterator> functionIterator, T originalArgument) { while (functionIterator.hasNext()) { Function function = functionIterator.next(); T result = function.apply(originalArgument); if (result != originalArgument) { return result; } } return originalArgument; } public static String stringOf(int repetitions, String string) { StringBuilder buffer = new StringBuilder(); while (repetitions-- > 0) { buffer.append(string); } return buffer.toString(); } /** * Indicates whether the elements of two iterators's ranges are equal. * * @param it1 * the first iterator to test. * @param it2 * the second iterator to test. * @return true if the elements of the two iterator's ranges are equal. */ public static boolean equals(Iterator it1, Iterator it2) { while (it1.hasNext()) { if (!it2.hasNext()) { return false; } Object o1 = it1.next(); Object o2 = it2.next(); if (!o1.equals(o2)) { return false; } } if (it2.hasNext()) { return false; } return true; } /** * A replacement for {@link Object#equals(Object)} that can deal with * objects being null. * * @param o1 * the first object to test. * @param o2 * the second object to test. * * @return true if true if the two object are null or both equal each other, * false otherwise. */ public static boolean equals(Object o1, Object o2) { if (o1 == null) { return o2 == null; } else if (o2 == null) { return false; } return o1.equals(o2); } /** * Indicates that neither of two objects are null and the first equals the * second. * * @param o1 * the first object to test. * @param o2 * the second object to test. * @return true if both object are not null and are equal, false otherwise. */ public static boolean notNullAndEquals(Object o1, Object o2) { if (o1 == null || o2 == null) { return false; } return o1.equals(o2); } /** * Indicates that two objects are not null and not equal. * * @param o1 * the first object to test. * @param o2 * the second object to test. * @return true if both object are not null and not equal, false otherwise. */ public static boolean notNullAndDistinct(Object o1, Object o2) { if (o1 == null || o2 == null) { return false; } return !o1.equals(o2); } /** * Indicates whether all elements in collection satisfy the given predicate. * * @param collection * the collection of elements to test. * @param predicate * the predicate to test the elements within the collection. * @return true if all elements in the collection match the given predicate, * false otherwise. * @param * the type of the collections elements. */ public static boolean forAll(Collection collection, Predicate predicate) { boolean result = collection.stream().allMatch(predicate::apply); return result; } /** * Indicates whether all elements in iterator's range satisfy the given predicate. * * @param iterator * the iterator over elements to test. * @param predicate * the predicate to test the elements within the iterator's range. * @return true if all elements in the iterator's range match the given predicate, * false otherwise. * @param * the type of the elements iterated over. */ public static boolean forAll(Iterator iterator, Predicate predicate) { while (iterator.hasNext()) { E element = iterator.next(); boolean predicateResult = predicate.apply(element); if ( ! predicateResult) { return false; } } return true; } /** * Indicates whether there is an element in iterator's range that satisfies * the given predicate. * * @param iterator * the iterator whose range of elements are to be tested. * @param predicate * the predicate to test the elements within the iterator's * range. * @return true if any element in the iterator's range match the given * predicate, false otherwise. * @param * the type of the iterators range elements. */ public static boolean thereExists(Iterator iterator, Predicate predicate) { while (iterator.hasNext()) { if (predicate.apply(iterator.next())) { return true; } } return false; } /** * Indicates whether there is an element in collection that satisfies the * given predicate. * * @param collection * the collection of elements to test. * @param predicate * the predicate to test the elements within the collection. * @return true if any element in the collection match the given predicate, * false otherwise. * @param * the type of the collections elements. */ public static boolean thereExists(Collection collection, Predicate predicate) { boolean result = collection.stream().anyMatch(predicate::apply); return result; } /** * Indicates whether there is a true element in array. * * @param array the array of booleans. * @return true if any element in the collection is true, false otherwise. */ public static boolean thereExists(boolean[] array) { for (boolean element : array) { if (element) { return true; } } return false; } /** * Adds all elements of two collections to a new LinkedList. * * @param c1 * the first collection to add elements from. * @param c2 * the second collection to add elements from. * @return a LinkedList containing the elements from both input collections. * @param * the type of the collections elements. */ public static List union(Collection c1, Collection c2) { List result = new LinkedList(); result.addAll(c1); result.addAll(c2); return result; } /** * Adds all elements of given collections to a new LinkedList. * * @param collections * the collections whose elements should be added to the returned * list. * @return a new Linked List containing all the elements from the given * collections. * @param * the type of the collections elements. */ public static List addAllToANewList(Collection... collections) { LinkedList result = new LinkedList(); for (Collection c : collections) { result.addAll(c); } return result; } public static String times(int level, String string) { StringBuilder result = new StringBuilder(); while (level-- > 0) { result.append(string); } return result.toString(); } /** * Creates PrintStream from file name checking for errors and throwing * appropriate {@link Error}s. * * @param fileName * the name of the file a print stream is to be created for. * @return the PrintStream against the given file. */ public static PrintStream getPrintStream(String fileName) { // use buffering PrintStream output; try { output = new PrintStream(fileName); } catch (IOException e) { throw new Error(e.getMessage()); } return output; } public static T getFirstOrNull(Iterator i) { if (i.hasNext()) { return i.next(); } return null; } public static T getFirstOrNull(Collection c) { return getFirstOrNull(c.iterator()); } /** * Returns the last element of a list or null, if empty. * * @param list * the list whose last element is to be returned. * @return the last element in the list or null if the list is empty. * @param * the type of the elements in the list. */ public static E getLast(List list) { if (list.isEmpty()) { return null; } return list.get(list.size() - 1); } public static T getFirst(Iterator i) { return i.next(); } public static T getFirst(Collection c) { return getFirst(c.iterator()); } /** * Return all but the first element in an iterator's range, in a newly made * list. * * @param i * the iterator to get rest from. * @return all but the first element in the iterator's range, in a newly * made list. * @param * the type of the elements in the iterator's range. */ public static List getRest(Iterator i) { if (!i.hasNext()) { throw new Error("Util.getRest called on empty iterator"); } i.next(); List result = listFrom(i); return result; } /** * Return all but the first element in a collection, in iteration order, in * a newly made list. * * @param c * the collection to get rest from. * @return all but the first element in the collection, in a newly made * list. * @param * the type of the collections elements. */ public static List getRest(Collection c) { return getRest(c.iterator()); } public static E getFirstSatisfyingPredicateOrNull( Iterator i, Predicate p) { while (i.hasNext()) { E o = i.next(); if (p.apply(o)) { return o; } } return null; } public static E getFirstSatisfyingPredicateOrNull( Collection c, Predicate p) { return getFirstSatisfyingPredicateOrNull(c.iterator(), p); } /** * Returns the first result of applying a given function to the elements of * a collection, or null if all such results are * null. * * @param c * the collection whose elements are to be mapped by the given * function. * @param f * the function to map the given elements with. * @return the first result of applying the given function to the elements * that is not null, otherwise null. * @param * the type of the give collections arguments and the type of the * argument to the given function. * @param * the result type of applying the given function to an element * in the given collection. */ public static R getFirstNonNullResultOrNull(Collection c, Function f) { R result = null; Optional first = c.stream().map(a -> f.apply(a)) .filter(r -> r != null).findFirst(); if (first.isPresent()) { result = first.get(); } return result; } public static E findFirst(Collection c, Predicate p) { return getFirstSatisfyingPredicateOrNull(c.iterator(), p); } public static E findFirst(Iterator i, Predicate p) { return getFirstSatisfyingPredicateOrNull(i, p); } public static int getIndexOfFirstSatisfyingPredicateOrMinusOne(Collection c, Predicate p) { int i = 0; for (E e : c) { if (p.apply(e)) { return i; } i++; } return -1; } public static Set intersection(Collection c1, Collection c2) { LinkedHashSet result = new LinkedHashSet(); for (T element : c1) { if (c2.contains(element)) { result.add(element); } } return result; } /** * Indicates whether two collections intersect. * * @param c1 * the first collection to test. * @param c2 * the second collection to test. * @return true if the two collections intersect. * @param * the type of the elements in the first collection. * @param * the type of the elements in the second collection. */ public static boolean intersect(Collection c1, Collection c2) { boolean result; // Optimization: Traverse the smaller list. if (c1.size() < c2.size()) { result = c1.stream().filter(e -> c2.contains(e)).findAny() .isPresent(); } else { result = c2.stream().filter(e -> c1.contains(e)).findAny() .isPresent(); } return result; } /** * A structure for * {@link Util#selectPair(List, Predicate, Predicate, BinaryPredicate)} and * {@link Util#selectPairInEitherOrder(List, Predicate, Predicate, BinaryPredicate)} results. * * @param

the type of the pairs. */ public static class SelectPairResult

{ public SelectPairResult(P first, P second, int indexOfFirst, int indexOfSecond, P satisfiesFirstPredicate, P satisfiesSecondPredicate) { super(); this.first = first; this.second = second; this.indexOfFirst = indexOfFirst; this.indexOfSecond = indexOfSecond; this.satisfiesFirstPredicate = satisfiesFirstPredicate; this.satisfiesSecondPredicate = satisfiesSecondPredicate; } /** Element appearing first. */ public P first; /** Element appearing second. */ public P second; /** Index of element appearing first. */ public int indexOfFirst; /** Index of element appearing second. */ public int indexOfSecond; /** Element satisfying first predicate. */ public P satisfiesFirstPredicate; /** Element satisfying second predicate. */ public P satisfiesSecondPredicate; } /** * Returns the indices of first pair of elements of a list such that each of * them satisfies a respectively given unary predicate, and them both * satisfy a binary predicate, or null if there is no such pair. * * @param list * the elements to test. * @param unaryPredicate1 * the first predicate to test with. * @param unaryPredicate2 * the second predicate to test with. * @param binaryPredicate * the binary predicate to test with. * @return the indices of first pair of elements of a list such that each of * them satisfies a respectively given unary predicate, and them * both satisfy a binary predicate, or null if there is no such * pair. * @param * the type of the elements in the list. */ public static SelectPairResult selectPair(List list, Predicate unaryPredicate1, Predicate unaryPredicate2, BinaryPredicate binaryPredicate) { for (int i = 0; i != list.size(); i++) { final T o1 = list.get(i); if (unaryPredicate1.apply(o1)) { for (int j = i + 1; j != list.size(); j++) { final T o2 = list.get(j); if (unaryPredicate2.apply(o2) && binaryPredicate.apply(o1, o2)) { return new SelectPairResult(o1, o2, i, j, o1, o2); } } } } return null; } /** * Like {@link #selectPair(List, Predicate, Predicate, BinaryPredicate)} , * but the pair may be present in either order. The binary predicate, for * consistency, is always applied to (x1, x2) where * x1 is the element satisfying the first unary predicate (as * opposed to being the element that appears first), and where * x2 is the element satisfying the second unary predicate (as * opposed to being the element that appears second). * * @param list * the elements to test. * @param unaryPredicate1 * the first predicate to test with. * @param unaryPredicate2 * the second predicate to test with. * @param binaryPredicate * the binary predicate to test with. * @return Like * {@link #selectPair(List, Predicate, Predicate, BinaryPredicate)} * , but the pair may be present in either order. The binary * predicate, for consistency, is always applied to * (x1, x2) where x1 is the element * satisfying the first unary predicate (as opposed to being the * element that appears first), and where x2 is the * element satisfying the second unary predicate (as opposed to * being the element that appears second). * @param * the type of the elements in the list. */ public static SelectPairResult selectPairInEitherOrder( List list, Predicate unaryPredicate1, Predicate unaryPredicate2, BinaryPredicate binaryPredicate) { // straight implementation // for (int i = 0; i != list.size(); i++) { // final T o1 = list.get(i); // boolean o1SatisfiesPredicate1 = unaryPredicate1.evaluate(o1); // boolean o1SatisfiesPredicate2 = unaryPredicate2.evaluate(o1); // // for (int j = i + 1; j != list.size(); j++) { // final T o2 = list.get(j); // boolean o2SatisfiesPredicate1 = unaryPredicate1.evaluate(o2); // boolean o2SatisfiesPredicate2 = unaryPredicate2.evaluate(o2); // // if (o1SatisfiesPredicate1 && o2SatisfiesPredicate2) { // boolean o1AndO2SatisfyBinaryPredicate = binaryPredicate.evaluate(o1, // o2); // if (o1AndO2SatisfyBinaryPredicate) { // return new SelectPairResult(o1, o2, i, j, o1, o2); // } // } // // if (o2SatisfiesPredicate1 && o1SatisfiesPredicate2) { // boolean o2AndO1SatisfyBinaryPredicate = binaryPredicate.evaluate(o2, // o1); // if (o2AndO1SatisfyBinaryPredicate) { // return new SelectPairResult(o1, o2, i, j, o2, o1); // } // } // } // } // return null; // implementation optimized for minimizing the calls to the predicates. for (int i = 0; i != list.size(); i++) { final T o1 = list.get(i); boolean o1SatisfiesPredicate1 = unaryPredicate1.apply(o1); if (o1SatisfiesPredicate1) { boolean o1SatisfyingOfPredicate2AlreadyComputed = false; boolean o1SatisfiesPredicate2 = false; // initial value is // irrelevant (never // used). Just making // compiler happy. int j; for (j = i + 1; j != list.size(); j++) { final T o2 = list.get(j); boolean o2SatisfiesPredicate2 = unaryPredicate2.apply(o2); if (o2SatisfiesPredicate2) { boolean o1AndO2SatisfyBinaryPredicate = binaryPredicate .apply(o1, o2); if (o1AndO2SatisfyBinaryPredicate) { return new SelectPairResult(o1, o2, i, j, o1, o2); } } else { boolean o2SatisfiesPredicate1 = unaryPredicate1 .apply(o2); if (o2SatisfiesPredicate1) { if (!o1SatisfyingOfPredicate2AlreadyComputed) { o1SatisfiesPredicate2 = unaryPredicate2 .apply(o1); o1SatisfyingOfPredicate2AlreadyComputed = true; } if (o1SatisfiesPredicate2) { boolean o2AndO1SatisfyBinaryPredicate = binaryPredicate .apply(o2, o1); if (o2AndO1SatisfyBinaryPredicate) { return new SelectPairResult(o1, o2, i, j, o2, o1); } } } } } } else { boolean o1SatisfiesPredicate2 = unaryPredicate2.apply(o1); if (o1SatisfiesPredicate2) { for (int j = i + 1; j != list.size(); j++) { final T o2 = list.get(j); boolean o2SatisfiesPredicate1 = unaryPredicate1 .apply(o2); if (o2SatisfiesPredicate1) { boolean o2AndO1SatisfyBinaryPredicate = binaryPredicate .apply(o2, o1); if (o2AndO1SatisfyBinaryPredicate) { return new SelectPairResult(o1, o2, i, j, o2, o1); } } } } } } return null; } /** * Returns two lists: one containing the elements of a list with indices * from 0 to i - 1, and another containing elements of indices i + 1 to the * last, excluding j. * * @param list * the list whose elements are to be sliced into two lists. * @param i * the index of the element to slice the list into two. * @param j * the index of an element > i to be excluded from the second * slice. * @return two lists: one containing the elements of a list with indices * from 0 to i - 1, and another containing elements of indices i + 1 * to the last, excluding j. * @param * the type of the elements in the list. */ public static Pair, List> slicesBeforeIAndRestWithoutJ( List list, int i, int j) { Pair, List> result = new Pair<>(new LinkedList<>(), new LinkedList<>()); for (int k = 0; k != i; k++) { result.first.add(list.get(k)); } for (int k = i + 1; k != list.size(); k++) { if (k != j) { result.second.add(list.get(k)); } } return result; } /** * Adds elements contained in c1 but not c2 to a given collection result. * * @param c1 * the elements to be placed in the result if they are not in the * second collection. * @param c2 * the elements not be added to the result. * @param result * the collection to be returned as the result. * @return result with elements contained in c1 that are not in c2 added to * it. * @param * the type of the elements. */ public static Collection setDifference(Collection c1, Collection c2, Collection result) { c1.stream().filter(e -> !c2.contains(e)).forEach(result::add); return result; } /** * Adds elements contained in c1 but not c2 to a new linked list and returns * it. * * @param c1 * the elements to be placed in the result if they are not in the * second collection. * @param c2 * the elements not be added to the result. * @return a new LinkedList with elements contained in c1 that are not in c2 * added to it. * @param * the type of the elements. */ public static List setDifference(Collection c1, Collection c2) { return (List) setDifference(c1, c2, new LinkedList()); } /** * Adds elements contained in c1 but not c2 to a new linked list and returns * it. * * @param c1 * the elements to be placed in the result if they are not in the * second collection. * @param c2 * the elements not be added to the result. * @return a new LinkedList with elements contained in c1 that are not in c2 * added to it. * @param * the type of the elements. */ public static List subtract(Collection c1, Collection c2) { return (List) setDifference(c1, c2, new LinkedList()); } public static String camelCaseToSpacedString(String camel) { StringBuilder result = new StringBuilder(); int i = 0; while (i < camel.length()) { char c = camel.charAt(i); if (Character.isUpperCase(c) && i != 0) { result.append(' '); int initialUpperCaseLetterIndex = i; while (i < camel.length() && Character.isUpperCase(camel.charAt(i))) { // if this is upper case but next one is lower case, then // this is the first letter of a word, // so append space first. if (i > initialUpperCaseLetterIndex && i + 1 < camel.length() && Character.isLowerCase(camel.charAt(i + 1))) { result.append(' '); } result.append(Character.toLowerCase(camel.charAt(i))); i++; } } else { result.append(c); i++; } } return result.toString(); } /** * Gets a collection and returns it back if there are no repeated elements, * or an ArrayList with unique elements. * * @param c * the collection to be tested. * @return the given collection if there are no repreated elements, or an * ArrayList with unique elements. * @param * the type of the elements. */ public static Collection removeRepeatedNonDestructively(Collection c) { LinkedHashSet s = new LinkedHashSet(c); if (s.size() == c.size()) { return c; } return new ArrayList(s); } public static List removeNonDestructively(List list, int excludedIndex) { if (excludedIndex >= list.size()) { return list; } ArrayList newList = new ArrayList(); int i = 0; for (T element : list) { if (i != excludedIndex) { newList.add(element); } i++; } return newList; } /** * Returns a new linked list containing the elements of collection that do not * satisfy a predicate. * * @param collection * the collection of elements to be tested. * @param predicate * the predicate to be used to test the elements. * @return a new linked list containing the elements of list that do not * satisfy a predicate. * @param * the type of the elements. */ public static LinkedList removeNonDestructively(Collection collection, Predicate predicate) { LinkedList result = collection.stream() .filter(e -> !predicate.apply(e)) .collect(toLinkedList()); return result; } /** * Returns a new linked hash set containing the elements of set that do not * satisfy a predicate. * * @param set * the set of elements to be tested. * @param predicate * the predicate to be used to test the elements. * @return a new linked hash set containing the elements of set that do not * satisfy a predicate. * @param * the type of the elements. */ public static LinkedHashSet removeFromSetNonDestructively(Set set, Predicate predicate) { LinkedHashSet result = set.stream() .filter(e -> !predicate.apply(e)) .collect(toLinkedHashSet(set.size())); return result; } /** * Returns a new linked hash set containing the elements of array list that do not * satisfy a predicate. * * @param arrayList * the array list of elements to be tested. * @param predicate * the predicate to be used to test the elements. * @return a new array list containing the elements of set that do not * satisfy a predicate. * @param * the type of the elements. */ public static ArrayList removeFromArrayListNonDestructively(ArrayList arrayList, Predicate predicate) { ArrayList result = new ArrayList(arrayList.size()); for (E element : arrayList) { if (!predicate.apply(element)) { result.add(element); } } return result; } /** * Returns a new linked list containing the elements of collection that are not equal to * a given one. * * @param collection * the collection of elements to be tested. * @param element * the element to be removed * @return a new linked list containing the elements of list that are not equal to the * given element. * @param * the type of the elements. */ public static List removeNonDestructively(Collection collection, T element) { List result = removeNonDestructively(collection, Equals.make(element)); return result; } public static List makeAListByReplacingFirstOccurrenceOfElementInAListWithAnotherList( List list, T element, List anotherList) { ArrayList result = new ArrayList(); boolean replacementAlreadyHappened = false; for (T someElement : list) { if (!replacementAlreadyHappened && someElement.equals(element)) { result.addAll(anotherList); replacementAlreadyHappened = true; } else { result.add(someElement); } } return result; } /** * Returns list of results of application of a function to pairs of elements * with same indices on two given lists. This is based on a Haskell function * of same name. * * @param function * the function to be applied to the paired elements from each * list. * @param list1 * a list of the first arguments to be zipped. * @param list2 * a list of the second arguments to be zipped. * @return a list of results of application of given function to pairs of * elements with same indices in two given lists. * @param * the type of the elements of list 1. * @param * the type of the elements of list 2. * @param * the type of the result of applying the given function to the * given pair of arguments. */ public static List zipWith( BinaryFunction function, List list1, List list2) { List result = new LinkedList(); Iterator i1 = list1.iterator(); Iterator i2 = list2.iterator(); while (i1.hasNext()) { A1 t1 = i1.next(); A2 t2 = i2.next(); R application = function.apply(t1, t2); result.add(application); } return result; } /** * Returns list of results of application of a function to triples of * elements with same indices on three given lists. This is based on a * Haskell function of same name. * * @param function * the function to be applied to the paired elements from each * list. * @param list1 * a list of the first arguments to be zipped. * @param list2 * a list of the second arguments to be zipped. * @param list3 * a list of the third arguments to be zipped. * @return a list of results of application of given function to triples of * elements with same indices in three given lists. * @param * the type of the elements of list 1. * @param * the type of the elements of list 2. * @param * the type of the elements of list 3. * @param * the type of the result of applying the given function to the * given triple of arguments. */ public static List zip3With( TernaryFunction function, List list1, List list2, List list3) { List result = new LinkedList(); Iterator i1 = list1.iterator(); Iterator i2 = list2.iterator(); Iterator i3 = list3.iterator(); while (i1.hasNext() && i2.hasNext() && i3.hasNext()) { A1 f1 = i1.next(); A2 f2 = i2.next(); A3 f3 = i3.next(); R application = function.apply(f1, f2, f3); result.add(application); } return result; } /** * Returns same list if none of its elements gets evaluated to a distinct * object by a replacement function, or a new list equal to the original one * but for having elements replaced by their replacements as provided by * same replacement function. * * @param list * the elements to be mapped. * @param replacementFunction * the element replacement function. * @return the same list if none of its elements gets evaluated to a * distinct object by a replacement function, or a new list equal to * the original one but for having elements replaced by their * replacements as provided by same replacement function. * @param * the type of the elements in the list. */ public static List replaceElementsNonDestructively(List list, Function replacementFunction) { List replacementList = null; ListIterator it = list.listIterator(); while (it.hasNext()) { E element = it.next(); E replacement = replacementFunction.apply(element); if (replacement != element) { replacementList = new ArrayList(list); replacementList.set(it.previousIndex(), replacement); break; } } if (replacementList == null) { return list; } it = replacementList.listIterator(it.nextIndex()); while (it.hasNext()) { E element = it.next(); E replacement = replacementFunction.apply(element); if (replacement != element) { it.set(replacement); } } return replacementList; } /** * Evaluates replacement function on i-th element of given list * and returns a new list with -ith element replaced by the result, * if the result is different from the original element, * or the same list if the result is equal to the original element. * * @param list * the list. * @param i the index of the element to be possibly replaced * @param replacementFunction * the element replacement function. * @return the same list if the i-th element gets evaluated to itself, * or a new (array) list with copied elements but for the i-th, * which gets replaced by the evaluation result. * @param * the type of the elements in the list. */ public static List replaceElementNonDestructively( List list, int i, Function replacementFunction) { E element = list.get(i); E evaluationResult = replacementFunction.apply(element); List result; if (evaluationResult.equals(element)) { result = list; } else { result = new ArrayList(list); result.set(i, evaluationResult); } return result; } public static boolean isPairWiseTrue(BinaryPredicate p, Collection c1, Iterator it2) { return isPairWiseTrue(p, c1.iterator(), it2); } public static boolean isPairWiseTrue(BinaryPredicate p, Iterator it1, Collection c2) { return isPairWiseTrue(p, it1, c2.iterator()); } public static boolean isPairWiseTrue(BinaryPredicate p, Iterator it1, Iterator it2) { while (it1.hasNext() && it2.hasNext()) { T1 t1 = it1.next(); T2 t2 = it2.next(); if (!p.apply(t1, t2)) { return false; } } if (it1.hasNext() != it2.hasNext()) { return false; } return true; } public static boolean isPairWiseTrue(BinaryPredicate p, Collection c1, Collection c2) { if (c1.size() != c2.size()) { return false; } Iterator it1 = c1.iterator(); Iterator it2 = c2.iterator(); while (it1.hasNext()) { T1 t1 = it1.next(); T2 t2 = it2.next(); if (!p.apply(t1, t2)) { return false; } } return true; } public static List setNonDestructively(List list, int index, T newElement) { List result = new LinkedList(list); result.set(index, newElement); return result; } /** * Returns a given iterator after iterating over its first element. * * @param iterator * the iterator to iterate over its first element. * @return the iterator after it has been moved past its first element. * Throws error if the iterator's range is empty. * @param * the type of the elements in the iterators range. */ public static Iterator removeFirst(Iterator iterator) { if (iterator.hasNext()) { iterator.next(); return iterator; } Util.fatalError("Iterator without elements received by Util.removeFirst(Iterator)"); return null; } public static List getAllButFirst(List list) { Iterator iterator = list.iterator(); iterator.next(); LinkedList result = new LinkedList(); addAll(result, iterator); return result; } /** * Compares two integers, taking into account that -1 means "infinite", * using the same return value convention as {@link Comparator}. * * @param limit1 * the first integer to compare. * @param limit2 * the second integer to compare. * @return the comparison between the two given integers, taking into * account that -1 means "infinite", using the same return value * convention as {@link Comparator}. * */ public static int compareIntegersWithMinusOneMeaningInfinite(int limit1, int limit2) { if (limit1 == -1) { if (limit2 == -1) { return 0; } else { return +1; } } else { if (limit2 == -1) { return -1; } else { return limit1 - limit2; } } } /** * Indicates whether an iterator's range contains a given element. * * @param iterator * the iterator whose range is to be tested. * @param element * the element to test if it is in the given iterators range. * @return true if the given element is in the given iterators range. * @param * the type of the elements. */ public static boolean contains(Iterator iterator, E element) { while (iterator.hasNext()) { if (iterator.next().equals(element)) { return true; } } return false; } /** * Indicates whether an element appears in a list from a given position. * * @param list * the list whose elements are to be tested. * @param i * the starting position in the list to start testing from. * @param element * the element to test if it is in the given sublist. * @return true if the element appears in the list from a given position, * false otherwise. * @param * the type of the elements. */ public static boolean listFromIContains(ArrayList list, int i, E element) { ListIterator iterator = list.listIterator(i); boolean result = contains(iterator, element); return result; } /** * Indicates whether an element appears in a list in a position up to, but * different from, i. * * @param list * the list whose elements are to be tested. * @param i * the index in the list that are to be tested to. * @param element * the element to test if its is in the given sublist. * @return true if the element appears in the list is a position up to, but * different from, i. * @param * the type of the elements. */ public static boolean listUpToIExclusiveContains(ArrayList list, int i, E element) { Iterator iterator = list.iterator(); for (int j = 0; iterator.hasNext() && j != i; j++) { E element2 = iterator.next(); if (element2.equals(element)) { return true; } } return false; } public static void removeAll(Set c, Predicate p) { List toBeRemoved = collectToList(c, p); c.removeAll(toBeRemoved); } public static void removeAll(Map map, Collection keysToRemove) { for (K key : keysToRemove) { map.remove(key); } } public static boolean lessThan(Rational r1, Rational r2) { int comparison = r1.compareTo(r2); return comparison == -1; } public static boolean lessThanOrEqualTo(Rational r1, Rational r2) { int comparison = r1.compareTo(r2); return comparison == -1 || comparison == 0; } public static boolean greaterThan(Rational r1, Rational r2) { int comparison = r1.compareTo(r2); return comparison == 1; } public static boolean equalValues(Rational r1, Rational r2) { int comparison = r1.compareTo(r2); return comparison == 0; } public static boolean greaterThanOrEqualTo(Rational r1, Rational r2) { int comparison = r1.compareTo(r2); return comparison == 0 || comparison == 1; } public static boolean equals(Rational rational, int integer) { return rational.compareTo(integer) == 0; } /** * Removes the elements that satisfy a predicate from a list. * * @param list * the list of elements to be tested. * @param predicate * the predicate to test the elements on the list with. * @param * the type of the elements. */ public static void removeElementsSatisfying(List list, Predicate predicate) { ListIterator iterator = list.listIterator(); while (iterator.hasNext()) { E element = iterator.next(); if (predicate.apply(element)) { iterator.remove(); } } } /** * Removes the elements that satisfy a predicate from a set -- works for * sets not containing null elements only. * * @param set * the set of elements to be tested. * @param predicate * the predicate to test the elements on the set with. * @param * the type of the elements. */ public static void removeElementsSatisfying(Set set, Predicate predicate) { boolean removed; do { removed = false; E element = getFirstSatisfyingPredicateOrNull(set, predicate); if (element != null) { set.remove(element); removed = true; } } while (removed); } public static Pair pair(T first, T second) { return new Pair(first, second); } /** * Returns an object's toString() result, or string "null" if object is * null. * * @param object * the object to be toString'd. * @return the object's toString() result, or string "null" if the object is * null. */ public static String toStringOrNull(Object object) { if (object == null) { return "null"; } return object.toString(); } /** * Returns +1 if given int is greater than 0, 0 if it is 0, and -1 if it is * less than 0. * * @param integer * the integer to be tested. * @return +1 if given int is greater than 0, 0 if it is 0, and -1 if it is * less than 0. */ public static int signal(int integer) { if (integer == 0) { return 0; } else if (integer > 0) { return +1; } return -1; } /** * Creates a map from a list of keys and a list of values. * * @param keys * a list of keys to be contained in the returned map. * @param values * a list of values to be contained in the returned map. * @return a map from the given lists of keys and values. * @param * the type of the keys. * @param * the type of the values. */ public static Map mapFromListOfKeysAndListOfValues( List keys, List values) { if (keys.size() != values.size()) { throw new Error( "mapFromListOfKeysAndListOfValues requires two lists of same size but got " + keys + " with " + keys.size() + " elements and " + values + " with " + values.size() + " elements."); } LinkedHashMap result = new LinkedHashMap(); Iterator keysIterator = keys.iterator(); Iterator valuesIterator = values.iterator(); while (keysIterator.hasNext()) { K key = keysIterator.next(); V value = valuesIterator.next(); result.put(key, value); } return result; } /** * Given map1 and map2, returns a new map such that map(K) = map2(map1(K)) * * @param map1 * the first map to compose. * @param map2 * the second map to compose. * @return a new map such that map(K) = map2(map1(K)) * @param * the type of map1's keys. * @param * the type of map1's values and map2's keys. * * @param * the type of map2's values. */ public static Map composeMaps(Map map1, Map map2) { Map result = new LinkedHashMap(); for (Map.Entry entry : map1.entrySet()) { K key = entry.getKey(); V1 value1 = entry.getValue(); V2 value2 = map2.get(value1); result.put(key, value2); } return result; } /** * Wait for some time, throwing an error in case of an exception. * * @param time * the time in milliseconds to wait. */ public static void waitOrThrowError(long time) { try { Thread.sleep(time); } catch (Exception e) { throw new Error("Unexpected exception:", e); } } /** * Returns the first object in an array that is an instance of a given * class. * * @param clazz * the class of the object to be found. * @param args * the elements to be tested if they are of the given class. * @return the first object in the given args array that is an instance of * the given class. */ public static Object getObjectOfClass(Class clazz, Object[] args) { for (Object object : args) { if (clazz.isInstance(object)) { return object; } } return null; } /** * Incrementally calculates component-wise averages, given previously * calculated averages (out of n numbers) and a list of new numbers. The * average list is filled with the appropriate number of zeros if it is * empty. The result is stored in-place, destroying the previous average * list. * * @param average * previously calculated averages. * @param n * averages out of 'n' numbers. * @param newItems * new numbers. * @return an incrementally calculated component-wise average. */ static public List incrementalComputationOfComponentWiseAverage( List average, int n, List newItems) { if (average == null) { fatalError("Util.incrementalComputationOfComponentWiseAverage must receive a non-null List"); } if (average.size() == 0) { for (int i = 0; i != newItems.size(); i++) { average.add(new Double(0)); } } for (int i = 0; i != newItems.size(); i++) { double currentAverage = ((Double) average.get(i)).doubleValue(); double newItem = ((Double) newItems.get(i)).doubleValue(); double newAverage = (currentAverage * n + newItem) / (n + 1); average.set(i, new Double(newAverage)); } return average; } /** * A more general version of incrementalComputationOfComponentWiseAverage(List, int, * List) that operates on lists of lists of arbitrary depth, * including depth 0, that is, on {@link Number}s. It is in-place and * returns average if given objects are lists, or returns a new * Number otherwise. * * @param average * previously calculated averages. * @param n * averages out of 'n' numbers. * @param newItems * new numbers. * @return an incrementally calculated component-wise average. */ @SuppressWarnings("unchecked") public static Object incrementalComponentWiseAverageArbitraryDepth( Object average, int n, Object newItems) { if (average instanceof Number) { return (((Number) average).doubleValue() * n + ((Number) newItems) .doubleValue()) / (n + 1); } ListIterator averageIterator = ((List) average).listIterator(); ListIterator newItemsIt = ((List) newItems).listIterator(); while (averageIterator.hasNext()) { Object averageElement = averageIterator.next(); Object newItemsElement = newItemsIt.next(); Object newAverageElement = incrementalComponentWiseAverageArbitraryDepth( averageElement, n, newItemsElement); if (newAverageElement != averageElement) { averageIterator.set(newAverageElement); } } return average; } /** * Given an array a, returns a map from each string in it to * the immediately following object. More precisely, returns a map mapping * each String s in position i of a * to the object in position i+1 of a, ignoring * the remaining elements. * * @param arguments * the arguments to be processed. * @return a map from each string in the given arguments array to the * immediately following object. */ public static Map getMapWithStringKeys(Object[] arguments) { Map map = new HashMap(); for (int i = 0; i < arguments.length; i++) { Object argument = arguments[i]; if (argument instanceof String) { String variable = (String) argument; Object value = arguments[++i]; map.put(variable, value); } } return map; } /** * Returns a function that returns a new iterator to the given collection * each time is it invoked. * * @param c * the collection the returned function is to create an iterator * over whenever it is applied. * @return a function that returns a new iterator to the given collection * each time it is invoked. * @param the type of the elements. */ static public NullaryFunction> getIteratorNullaryFunction( final Collection c) { return new NullaryFunction>() { @Override public Iterator apply() { return c.iterator(); } }; } /** * Takes a list of lists, a dimension index (0 for rows, 1 for columns) and * an index (either row or column index), and returns the corresponding * slice (data[index,*] if dimension is 0, or data[*,index] if dimension is * 1). * * @param data * a list of lists * @param dimension * a dimension index (0 for rows, 1 for columns) * @param index * an row or column index. * @return the corresponding slice * @param * the type of the elements. */ public static List matrixSlice(List> data, int dimension, int index) { if (dimension == 0) { return data.get(index); } List result = new LinkedList(); for (Iterator> rowIt = data.iterator(); rowIt.hasNext();) { List row = rowIt.next(); result.add(row.get(index)); } return result; } public static String[] makeArrayFilledOutWith(String element, int length) { String[] result = new String[length]; for (int i = 0; i < result.length; i++) { result[i] = element; } return result; } public static List getFirstColumnAsList(String[][] stringMatrix) { List list = new LinkedList(); for (int i = 0; i < stringMatrix.length; i++) { list.add(stringMatrix[i][0]); } return list; } public static String[] getSecondColumnAsArray(String[][] stringMatrix) { String[] array = new String[stringMatrix.length]; for (int i = 0; i < stringMatrix.length; i++) { array[i] = stringMatrix[i][1]; } return array; } /** * Randomly picks an element of given array using a given {@link Random} * number generator. * * @param random * the random number generator to use. * @param items * the items from which an element is to be randomly picked from. * @return the randomly picked element from the given array of items. */ public static Object randomPick(Random random, Object[] items) { int index = random.nextInt(items.length); Object result = items[index]; return result; } /** * Randomly picks n elements (possibly repeated) of given array * using a given {@link Random} number generator. * * @param n * the number of items to randomly pick. * @param random * the random number generator to use. * @param items * the items from which an element is to be randomly picked from. * @return a list of elements (possibly repeated) randomly selected from the * given array of items. */ public static ArrayList randomPick(int n, Random random, Object[] items) { ArrayList result = new ArrayList(n); for (int i = 0; i != n; i++) { result.add(randomPick(random, items)); } return result; } /** * Randomly picks an element of given list ({@link ArrayList}s will be most * efficient) using a given {@link Random} number generator. * * @param random * the random number generator to use. * @param items * the items from which an element is to be randomly picked from. * @return the randomly picked element from the given list of items. * @param * the type of the elements. */ public static E randomPick(Random random, List items) { int index = random.nextInt(items.size()); E result = items.get(index); return result; } /** * Randomly picks n elements (possibly repeated) of given list * ({@link ArrayList}s will be most efficient) using a given {@link Random} * number generator. * * @param n * the number of items to randomly pick. * @param random * the random number generator to use. * @param items * the items from which an element is to be randomly picked from. * @return a list of elements (possibly repeated) randomly selected from the * given list of items. * @param * the type of the elements. */ public static List randomPick(int n, Random random, List items) { List result = new ArrayList(n); for (int i = 0; i != n; i++) { result.add(randomPick(random, items)); } return result; } /** * Determines whether all elements in collection are * {@link Object#equals(Object)}, including null. * * @param collection * the collection of elements to be tested. * @return true of all elements in the given collection are equal, including * null. * @param * the type of the elements. */ public static boolean allEqual(Collection collection) { boolean result = true; Iterator iterator = collection.iterator(); if (iterator.hasNext()) { E previous = iterator.next(); while (result && iterator.hasNext()) { E nextOne = iterator.next(); if (!equals(nextOne, previous)) { result = false; } } } return result; } public static T pickElementInFirstCollectionButNotSecondAndNotEqualTo( Collection collection1, Collection collection2, T valueItMustBeDifferentFrom) { for (T value1 : collection1) { if (!value1.equals(valueItMustBeDifferentFrom) && !collection2.contains(value1)) { return value1; } } return null; } public static Set copySetWithoutThisElement( Collection collection, T excludedElement) { Set result; result = new LinkedHashSet(collection); result.remove(excludedElement); return result; } /** * Pushes all elements of a collection into a stack and returns the size of * this collection. * * @param stack * the stack to have elements pushed onto. * @param toBePushed * the elements to be pushed onto the given stack. * @return the number of elements pushed onto the stack. * @param * the type of the elements. */ public static int pushAll(Stack stack, Collection toBePushed) { for (E element : toBePushed) { stack.push(element); } return toBePushed.size(); } /** * Pops n elements from stack. * * @param stack * the stack to be popped. * @param n * the number of elements to be popped from the stack. * @param * the type of the elements. */ public static void popAll(Stack stack, int n) { for (int i = 0; i != n; i++) { stack.pop(); } } /** * Receives a collection of keys and returns a map from them to their * respective results from a given function. * * @param keys * the keys to be used as arguments to given function. * @param function * the function to apply to the given keys to generate * corresponding values. * @return a Map of the given keys with values generated from applying the * given function to the keys. * @param * the type of the keys. * @param * the type of the values. */ public static Map getFunctionMapForGivenKeys( Collection keys, Function function) { Map result = new LinkedHashMap(); for (K key : keys) { result.put(key, function.apply(key)); } return result; } /** * @return a {@link Collector} to a {@link LinkedList}. * @param * the type of the elements the constructed linked list should * contain. */ public static Collector> toLinkedList() { return Collectors.toCollection(() -> new LinkedList()); } /** * @return a {@link Collector} to a {@link LinkedHashSet}. * @param * the type of the elements the constructed linked hash set * should contain. */ public static Collector> toLinkedHashSet() { return Collectors.toCollection(() -> new LinkedHashSet()); } /** * @return a {@link Collector} to a {@link LinkedHashSet} with given initial * capacity. * @param initialCapacity * the initial capacity of the instantiated {@link LinkedHashSet} * @param * the type of the elements the constructed linked hash set * should contain. */ public static Collector> toLinkedHashSet(int initialCapacity) { return Collectors.toCollection(() -> new LinkedHashSet(initialCapacity)); } /** * @return a {@link Collector} to an array list with given initial capacity. * @param initialCapacity * the initial capacity of the instantiated {@link ArrayList}. * @param * the type of the elements the constructed array list should * contain. */ public static Collector> toArrayList(int initialCapacity) { return Collectors.toCollection(() -> new ArrayList(initialCapacity)); } /** * Attempts to cast an object to a given class, * and if that does not succeed, throws an error with a message generated from a template * following the format conventions of {@link String#format(String, Object...)}, * with formatting arguments being the object being cast, and the expected and actual received classes' simple names, * in this order. * @param clazz the class to be cast to * @param object the object to be cast * @param messageTemplate the message template from which an error message is generated * @return the cast object * @param object type * @param class type */ public static T2 castOrThrowError(Class clazz, T1 object, String messageTemplate) { T2 result; try { result = clazz.cast(object); } catch (ClassCastException e) { String message = String.format(messageTemplate, object, clazz.getSimpleName(), object.getClass().getSimpleName()); throw new Error(message); } return result; } /** * Given two objects, returns a pair in which either the first element satisfies given predicate, or neither object does. * @param t1 * type 1 * @param t2 * type 2 * @param predicate * a predicate * @return a pair in which either the first element satisfies given predicate, or neither object does. * @param the type of the pair's elements. */ public static Pair sortPairMakingFirstOneSatisfyPredicateIfPossible(T t1, T t2, Predicate predicate) { if (predicate.apply(t1)) { return Pair.make(t1, t2); } else { return Pair.make(t2, t1); } } /** * A utility method throwing an error to indicate that a method used by a default implementation of another method * has not been overridden. *

* This is useful in the following situation. * Suppose a class Vehicle (superClassName) provides a default implementation for checkUp() (nameOfMethodWhoseDefaultImplementationUsesThisMethod) * that assumes the Vehicle has tires in the first place, * and uses an abstract method tiresType() (thisMethodsName). Since a lot of vehicles do use tires, such default implementation is very convenient. * However, we do not want to make life harder for people extending Vehicle to represent vehicles without tires (such as a class Boat (thisClassName)), * and forcing them to implement tiresType() with some dummy code would be ugly and distracting. * Besides, the developer may not notice that checkUp() assumes tires, and as a result may not override it (as they should since Boat violates that assumption). * In that case, the dummy code in tiresType() code will be invoked even though it should not. *

* The solution is to change tiresType() from abstract to an implemented method simply invoking this Error-throwing safeguard utility. * If the developer overrides checkUp(), as they should in the case of Boat, the fact that tiresType() is no longer an abstract method * will prevent the compiler from insisting on its unnecessary implementation. * If the developer does not override checkUp() (for example, while extending Vehicle to a class Car), * but forgets to override tiresType() (since it is not abstract anymore, the compiler will not complain), * then there will be an Error thrown at run-time by this utility safeguard method. *

* In other words, because tiresType() is "abstract" only as a result of using a default, optional implementation, * we make it not technically abstract and required in compile-time, but still "abstract" in a run-time sense of * an implementation being demanded in case it is actually needed. * * @param thisClassName * the name of the class * @param thisMethodsName * the method name * @param superClassName * the super class name * @param namesOfMethodsWhoseDefaultImplementationUsesThisMethod * names of methods whose default implementation uses this method * @throws Error if one occurs */ public static void throwSafeguardError( String thisClassName, String thisMethodsName, String superClassName, String... namesOfMethodsWhoseDefaultImplementationUsesThisMethod) throws Error { String oneOf = namesOfMethodsWhoseDefaultImplementationUsesThisMethod.length > 1? "one of " : ""; throw new Error( thisMethodsName + " is being invoked but has not been overridden by " + thisClassName + ". " + "It is probably being invoked by the default implementation of " + oneOf + join(namesOfMethodsWhoseDefaultImplementationUsesThisMethod) + " in " + superClassName + ", unless some other overriding method invokes it. " + "If the default implementation of " + join(namesOfMethodsWhoseDefaultImplementationUsesThisMethod) + " in " + superClassName + " is being used, " + thisMethodsName + " should be overridden," + " or if " + thisMethodsName + " does not make sense for " + thisClassName + " (because of some assumption made by the default implementation of " + join(namesOfMethodsWhoseDefaultImplementationUsesThisMethod) + " that does not hold in " + thisClassName + "), then a new implementation of " + join(namesOfMethodsWhoseDefaultImplementationUsesThisMethod) + " should override the default one;" + " if on the other hand the default implementation of " + join(namesOfMethodsWhoseDefaultImplementationUsesThisMethod) + " has been overridden, then its new version, or some other overriding method, is invoking " + thisMethodsName + ", which (typically) should not happen (because " + thisMethodsName + " conforms to the assumptions made by the default" + " implementation of " + join(namesOfMethodsWhoseDefaultImplementationUsesThisMethod) + " and the overriding of the latter indicates that those assumptions probably do not hold anymore."); } public static PairOf> collectToLists(List collection, Predicate predicate) { List positive = new LinkedList(); List negative = new LinkedList(); collect(collection, positive, predicate, negative); PairOf> result = makePairOf(positive, negative); return result; } /** * Non-destructively replaces each element in collection by the elements of a list, if expander produces a non-null one when given the element, * returning the same List instance if no expansion is done. * @param list * a list * @param expander * an expander * @return if expansion occurred a new list with all the old elements plus the expansions, otherwise the input list. * @param the type of the list's elements. */ public static List nonDestructivelyExpandElementsIfFunctionReturnsNonNullCollection(List list, Function> expander) { List result = new LinkedList(); boolean expansionOccurred = false; for (T element : list) { Collection expansion = expander.apply(element); if (expansion == null) { result.add(element); } else { result.addAll(expansion); expansionOccurred = true; } } if ( ! expansionOccurred) { result = list; } return result; } public static final String MY_ASSERT_OFF = "com.sri.ai.util.myAssertOff"; // /** // * A java assert substitute that, unlike the standard one, is on by default and // * can be turned off by setting any value to property {@link #MY_ASSERT_OFF}. // * It throws an {@link AssertionError} with the given message. // * @param test // * result of the test // * @param message // * message to display if test failed. // */ // public static void myAssert(boolean test, String message) { // if ( ! test && System.getProperty(MY_ASSERT_OFF) == null) { // throw new AssertionError(message); // } // } // Commented out because it can have unsuspected performance impact even when testing is turned off. /** * Checks for a condition that needs to be true, or * throws an error with a given message. * This is similar to {@link #myAssert(boolean, NullaryFunction)}, * but is performed even if property {@link #MY_ASSERT_OFF} is not null, * since it is meant for errors that may occur due to * incorrect input by a user. * It throws an {@link Error} with the given message. * @param test * result of the test * @param message * message in thrown {@link Error}. */ public static void check(boolean test, NullaryFunction message) { if ( ! test) { throw new Error(message.apply()); } } /** * Checks for a condition that needs to be true, or * throws an error with a given message. * This is similar to {@link #myAssert(NullaryFunction, NullaryFunction)}, * but is performed even if property {@link #MY_ASSERT_OFF} is not null, * since it is meant for errors that may occur due to * incorrect input by a user. * It throws an {@link Error} with the given message. * @param test * result of the test * @param message * message in thrown {@link Error}. */ public static void check(NullaryFunction test, NullaryFunction message) { if (! test.apply()) { throw new Error(message.apply()); } } /** * A java assert substitute that, unlike the standard one, is on by default and * can be turned off by setting any value to property {@link #MY_ASSERT_OFF}. * It throws an {@link AssertionError} with the given message. * @param test * result of the test * @param message * message to display if test failed. */ public static void myAssert(boolean test, NullaryFunction message) { if ( ! test && System.getProperty(MY_ASSERT_OFF) == null) { throw new AssertionError(message.apply()); } } /** * Similar to {@link #myAssert(boolean, NullaryFunction)}, but takes nullary functions * for the test and the error message, and only executes them if property {@link #MY_ASSERT_OFF} is null, * thus maximizing performance when it isn't null. * * @param test * result of the test * @param message * message to display if test failed. */ public static void myAssert(NullaryFunction test, NullaryFunction message) { if (System.getProperty(MY_ASSERT_OFF) == null && ! test.apply()) { throw new AssertionError(message.apply()); } } // /** // * Similar to {@link #myAssert(boolean, String)}, but takes a nullary function // * for the test, and only executes it if property {@link #MY_ASSERT_OFF} is null, // * thus maximizing performance when it isn't null. // * // * @param test // * result of the test // * @param message // * message to display if test failed. // */ // public static void myAssert(NullaryFunction test, String message) { // if (System.getProperty(MY_ASSERT_OFF) == null && ! test.apply()) { // throw new AssertionError(message); // } // } // Commented out because it can have unsuspected performance impact even when testing is turned off. /** * Returns the entryIndex-th entry in a {@link LinkedHashMap}, * assuming there is such entry (throws an exception otherwise). * @param map * a map * @param entryIndex * an entry index * @return the entry at the given index * @param the map's key type * @param the map's value type */ public static Map.Entry getIthEntry(LinkedHashMap map, int entryIndex) { Map.Entry result; Iterator> iterator = map.entrySet().iterator(); for (int i = 0; i != entryIndex; i++) { iterator.next(); } result = iterator.next(); return result; } /** * Iterates given iterator till it has no more elements or it is past a given element (ignored if null), * detecting the passage through them with the identity comparison (==). * @param iterator * an iterator * @param element * an element * @param the type of the elements. */ public static void iterateTillPastElementByIdentity(Iterator iterator, T element) { boolean elementRequirementSatisfied = element == null; while (iterator.hasNext() && (!elementRequirementSatisfied)) { T current = iterator.next(); elementRequirementSatisfied = elementRequirementSatisfied || current == element; } } /** * Iterates given iterator till it has no more elements or it is past both given elements (ignored if null), * detecting the passage through them with the identity comparison (==). * @param iterator * an iterator * @param element1 * an element * @param element2 * an element * @param the type of the elements. */ public static void iterateTillPastBothElementsByIdentity(Iterator iterator, T element1, T element2) { boolean element1RequirementSatisfied = element1 == null; boolean element2RequirementSatisfied = element2 == null; while (iterator.hasNext() && (!element1RequirementSatisfied || !element2RequirementSatisfied)) { T current = iterator.next(); element1RequirementSatisfied = element1RequirementSatisfied || current == element1; element2RequirementSatisfied = element2RequirementSatisfied || current == element2; } } /** * Computes the rising factorial start^(n) defined as start(start + 1)...(start + n - 1). * @param start the first number to be multiplied * @param n the number of numbers to multiply, starting and rising from start * @return the rising factorial start^(n) */ public static Rational risingFactorial(long start, long n) { // more efficient implementation that works with smaller numbers than just multiplying numbers in sequence. // there are more efficient ways of doing this, though. long i; if (n == 0) { return Rational.ONE; } else if (n <= 16) { Rational r = new Rational(start); for (i = start + 1; i < start + n; i++) { r = r.multiply(i); } return r; } i = n / 2; Rational result = risingFactorial(start, i).multiply(risingFactorial(start + i, n - i)); return result; } /** * Computes the falling factorial (start)_n defined as start(start - 1)...(start - n + 1). * It does that by reducing the problem to a rising factorial ({@link #risingFactorial(long, long)}) * due to the equality (start)_n = (start - n + 1)^(n). * @param start the first number to be multiplied * @param n the number of numbers to multiply, starting and decreasing from start * @return the falling factorial (start)_n */ public static Rational fallingFactorial(long start, long n) { Rational result = risingFactorial(start - n + 1, n); return result; } /** * Computes the factorial of n. * It does that by reducing the problem to a rising factorial ({@link #risingFactorial(long, long)}) * due to the equality n! = 1^(n). * @param n the number whose factorial is returned * @return the factorial of n */ public static Rational factorial(long n) { Rational result = risingFactorial(1, n); return result; } /** * Computes the binomial coefficient choose(n, k) = n! / ((n - k)! k!). * It does that by reducing the problem to a falling factorial ({@link #fallingFactorial(long, long)}) * and a factorial ({@link #factorial(long)}) * due to the equality n! / ((n - k)! k!) = (n)_k / k!. * @param n the number of elements * @param k the number of elements selected for the set * @return the binomial coefficient */ public static Rational binomialCoefficient(long n, long k) { Rational result = fallingFactorial(n, k).divide(factorial(k)); return result; } /** * Applies a function to the values of a map, returning a new map, * or the same map instance if the function has always returned the same value object instances. * @param map the map * @param function the function * @param the type of keys * @param the type of values * @return a new map with each value v replaced by function(v), or the same map if f(v) == v for all v. */ public static Map mapValuesNonDestructively(Map map, Function function) { Map result = new LinkedHashMap(); boolean instanceChange = false; for (Map.Entry entry : map.entrySet()) { V value = entry.getValue(); V newValue = function.apply(value); if (newValue != value) { instanceChange = true; } result.put(entry.getKey(), newValue); } if (instanceChange) { return result; } else { return map; } } /** * Iterates over all elements in iterator's range and picks one with uniform probability. * * @param iterator the iterator * @param random a random number generator * @param the type of elements * @return a uniformly sampled element from the iterator's range using the random number generator. */ public static T pickUniformly(Iterator iterator, Random random) { List list = listFrom(iterator); T result = list.get(random.nextInt(list.size())); return result; } /** * Iterates over all elements in collection and picks one with uniform probability. * * @param collection the collection * @param random a random number generator * @param the type of elements * @return a uniformly sampled element from the iterator's range using the random number generator. */ public static T pickUniformly(Collection collection, Random random) { return pickUniformly(collection.iterator(), random); } /** * Iterates over a random subset of another iterator's range, * by selecting whether each element in it belong to the subset or not * with 0.5 probability. * @param iterator iterator * @param random random generator * @param the type * @return a random sub-set */ public static Iterator pickSubSet(Iterator iterator, Random random) { return new EZIterator() { @Override protected T calculateNext() { if (iterator.hasNext()) { T next = iterator.next(); return random.nextBoolean()? next : null; } return null; } }; } /** * Returns an array list with k elements out of the given list, without replacement. * This means that the returned list contains the elements of k unique positions * in the original list. * If the list contains unique elements, then so will the returned list, * but elements may be repeated if they appear more than once in the original list. * Naturally, k needs to be no greater than the list's size, or an assertion error will be thrown. * @param list list * @param k number of elements to pick * @param random random generator * @param type of elements * @return a list of elements at k unique positions in the given list */ public static ArrayList pickKElementsWithoutReplacement(ArrayList list, int k, Random random) { ArrayList result; if (k == list.size()) { // unnecessary, but faster result = list; } else { myAssert(() -> k < list.size(), () -> "pickKElementsWithoutReplacement received k = " + k + " greater than list size " + list.size()); Set alreadyPicked = set(); result = new ArrayList(k); for (int i = 0; i != k; i++) { int j; do { j = random.nextInt(list.size()); } while (alreadyPicked.contains(j)); result.add(list.get(j)); alreadyPicked.add(j); } } return result; } /** * Returns an array list with up to k elements out of the given list * satisfying a given predicate, without replacement. * This means that the returned list contains the elements of k unique positions * in the original list. * If the list contains unique elements, then so will the returned list, * but elements may be repeated if they appear more than once in the original list. * The number of picked elements is the maximum of k * and the number of positions in the input list whose elements satisfy the predicate. * @param list the list of elements * @param k number of elements to pick * @param requirement requirement * @param random random generator * @param type of elements * @return a list of up to k elements at unique positions in the given list (picked without replacement). */ public static ArrayList pickUpToKElementsWithoutReplacement(ArrayList list, int k, Predicate requirement, Random random) { ArrayList result; Set alreadyPicked = set(); result = new ArrayList(k); for (int i = 0; i != k; i++) { int j; do { if (alreadyPicked.size() == list.size()) { return result; } do { j = random.nextInt(list.size()); } while (alreadyPicked.contains(j)); alreadyPicked.add(j); } while (!requirement.apply(list.get(j))); result.add(list.get(j)); } return result; } /** * Stores, in a given array list, up to k elements out of the input list * satisfying a given predicate, without replacement. * The number of elements collected is the maximum of k * and the number of positions in the input list whose elements satisfy the predicate. * @param list the list of elements * @param k number of elements to pick * @param requirement requirement * @param random random generator * @param type of elements */ public static void pickUpToKElementsWithoutReplacement(ArrayList list, int k, Predicate requirement, Random random, ArrayList destination) { Set alreadyPicked = set(); for (int i = 0; i != k; i++) { int j; do { if (alreadyPicked.size() == list.size()) { return; } do { j = random.nextInt(list.size()); } while (alreadyPicked.contains(j)); alreadyPicked.add(j); } while (!requirement.apply(list.get(j))); destination.add(list.get(j)); } } /** * Adapts an {@link Iterator} to an {@link Iterable} for use in enhanced for * loops. If {@link Iterable#iterator()} is invoked more than once, an * {@link IllegalStateException} is thrown. * @param iterator the iterator * @param the type of elements * @return the iterable for iterator */ public static Iterable in(final Iterator iterator) { assert iterator != null; class SingleUseIterable implements Iterable { private boolean used = false; @Override public Iterator iterator() { if (used) { throw new IllegalStateException("SingleUseIterable already invoked"); } used = true; return iterator; } } return new SingleUseIterable(); } /** * Same as {@link #union(Iterator)} applied to given collection's iterator. * @param maps the collection of maps * @param the type of keys * @param the type of values * @return a new map with all entries from all maps in a collection */ public static Map union(Collection> maps) { return union(maps.iterator()); } /** * Returns a new map with all entries from all maps in an iterator's range. * @param mapsIterator the maps iterator * @param the type of keys * @param the type of values * @return a new map with all entries from all maps in an iterator's range */ public static Map union(Iterator> mapsIterator) { return putAllFromAll(new LinkedHashMap(), mapsIterator); } /** * Puts all entries from all maps in the range of an iterator to a given map. * @param map the map * @param mapsIterator the maps iterator * @param the type of keys * @param the type of values * @return the given map with all entries from all maps in interator's range */ public static Map putAllFromAll(Map map, Iterator> mapsIterator) { for (Map eachMap : in(mapsIterator)) { map.putAll(eachMap); } return map; } /** * Creates an array list of size n, filled with a given value. * @param n the size of the array * @param value the value to fill the array with * @param the type of value * @return an array list of size n, filled with a given value. */ public static ArrayList fill(int n, T value) { ArrayList result = new ArrayList(n); for (int i = 0; i != n; i++) { result.add(value); } return result; } /** * Given an array list and a list of integers, returns an array list with the indexed elements in the indices order. * @param array the array from which to extract sub array. * @param indices the array of indices * @param the type of values * @return array list with the indexed elements in the indices order. */ public static ArrayList makeCopyWithGivenIndices(ArrayList array, List indices) { ArrayList result = new ArrayList(indices.size()); for (int i = 0; i != indices.size(); i++) { Integer ithIndex = indices.get(i); E elementAtIthIndex = array.get(ithIndex); result.add(elementAtIthIndex); } return result; } /** * Stores the elements from an iterable of iterables in an array list of array lists. * @param iterableOfIterables iterable of iterables * @return array of arrays * @param type */ public static ArrayList> storeIterableOfIterablesInArrayListOfArrayLists(Iterable> iterableOfIterables) { ArrayList> result; result = arrayList(); for (Iterable iterable : iterableOfIterables) { ArrayList innerArrayList = arrayList(); for (T element : iterable) { innerArrayList.add(element); } result.add(innerArrayList); } return result; } /** * Put given value in a list indexed by key, creating a new linked list if the map still does not contain the key. * @param mapToLists map to lists * @param key a key * @param value a value * @param key type * @param value type */ public static void putInListValue(Map> mapToLists, K key, V value) { List list; if (mapToLists.containsKey(key)) { list = mapToLists.get(key); } else { list = new LinkedList(); mapToLists.put(key, list); } list.add(value); } /** * Allocates an array list of given size filled with given value. * @param value a value * @param size size of list * @param type of elements * @return an array list of given size with all elements equal to given value */ public static ArrayList arrayListFilledWith(T value, int size) { ArrayList result = new ArrayList<>(size); for (int i = 0; i != size; i++) { result.add(value); } return result; } }