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

com.xyzwps.lib.dollar.Dollar Maven / Gradle / Ivy

The newest version!
package com.xyzwps.lib.dollar;

import com.xyzwps.lib.dollar.function.Function3;
import com.xyzwps.lib.dollar.function.ObjIntFunction;
import com.xyzwps.lib.dollar.iterable.Range;

import java.util.*;
import java.util.function.*;
import java.util.regex.Pattern;

import static com.xyzwps.lib.dollar.Helper.*;

/**
 * Where to start.
 * 

* TODO: optimize for RandomAccess * TODO: 写中文文档 * TODO: add examples */ public final class Dollar { /** * Create a stage chain from a {@link List}. * * @param list source list. Null is acceptable. * @param list element type * @return a list stage */ public static Seq $(List list) { return $.isEmpty(list) ? Seq.empty() : list::forEach; } /** * Create a stage chain from a map. * * @param map source map. Null is acceptable. * @param map key type * @param map value type * @return a map stage */ public static MESeq $(Map map) { return $.isEmpty(map) ? MESeq.empty() : map::forEach; } public static class $ { /** * Count the elements of a collection. * Return 0 if collection is null. * * @param collection which to handle * @param collection element type * @return count of elements in collection */ public static int size(Collection collection) { return collection == null ? 0 : collection.size(); } /** * Count the entries of a map. * Return 0 if map is null. * * @param map which to handle * @param type of keys * @param type of values * @return count of entries in map */ public static int size(Map map) { return map == null ? 0 : map.size(); } /** * Checks value to determine whether a public static value * should be returned in its place. The defaultValue * is returned when value is null. * * @param value The value to check * @param defaultValue The public static value * @param value type * @return resolved value */ public static T defaultTo(T value, T defaultValue) { return value == null ? defaultValue : value; } /** * Check value which is falsey or not. The values null, false, * 0(.0) and "" are falsey. * * @param value value to be checked * @return true if the value is falsey * @see #compact */ public static boolean isFalsey(Object value) { return value == null || Objects.equals(value, false) || "".equals(value) || Objects.equals(value, 0) || Objects.equals(value, 0L) || Objects.equals(value, 0.0) || Objects.equals(value, 0.0f); } /** * Creates a list of elements split into groups the length of size. * If list can't be split evenly, the final chunk will be the remaining elements. * * @param list The list to handle * @param size Chunk size which should be greater than 0. * @param Element type * @return new list of chunks */ public static List> chunk(List list, int size) { if (size < 1) { throw new IllegalArgumentException("Chunk size should be greater than 0."); } if (isEmpty(list)) { return new ArrayList<>(); } int listSize = list.size(); int chunksCapacity = listSize / size + 1; List> chunks = new ArrayList<>(chunksCapacity); List chunk = null; int counter = 0; int i = 0; for (T element : list) { if (counter == 0) { chunk = new ArrayList<>(size); } chunk.add(element); counter++; i++; if (counter == size || i == listSize) { chunks.add(chunk); chunk = null; counter = 0; } } return chunks; } /** * Filter list with the elements which are not falsey. *

* The definition of falsey can be seen at {@link #isFalsey} * * @param list The list to filter. Null is acceptable. * @param List element type * @return new compacted list * @see #isFalsey */ public static List compact(List list) { return filter(list, it -> !isFalsey(it)); } /** * Creates a new list which concatenating all lists in order. * * @param lists The lists to concatenate * @param Element type * @return concatenated new list */ @SafeVarargs public static List concat(List... lists) { if (lists.length == 0) { return new ArrayList<>(); } int capacity = 0; for (List list : lists) { if (isNotEmpty(list)) { capacity += list.size(); } } if (capacity == 0) { return new ArrayList<>(); } ArrayList result = new ArrayList<>(capacity); for (List list : lists) { if (isNotEmpty(list)) { result.addAll(list); } } return result; } /** * Iterate over the list and retaining the elements which are predicated true. * * @param list The list to iterate. Null is acceptable. * @param predicate Predicate function. Cannot be null. * @param Element type * @return new filtered list */ public static List filter(List list, Predicate predicate) { Objects.requireNonNull(predicate); return filter(list, (e, i) -> predicate.test(e)); } /** * Iterate over the list and retaining the elements which are predicated true. * * @param list The list to iterate. Null is acceptable. * @param predicate Predicate function with element index. Cannot be null. * @param Element type * @return new filtered list */ public static List filter(List list, BiPredicate predicate) { Objects.requireNonNull(predicate); if (list == null) { return new ArrayList<>(); } List result = new ArrayList<>(); int i = 0; for (T element : list) { if (predicate.test(element, i++)) { result.add(element); } } return result; } /** * Create a list. * * @param args elements of list * @param type of elements * @return new list */ @SafeVarargs public static List listOf(T... args) { List list = Arrays.asList(args); return list instanceof ArrayList ? (ArrayList) list : new ArrayList<>(list); } /** * Create a list from an {@link Iterator}. * * @param itr which provide elements * @param type of elements * @return new list */ public static List listFrom(Iterator itr) { List list = new ArrayList<>(); if (itr != null) { while (itr.hasNext()) list.add(itr.next()); } return list; } /** * Map a list to another. * * @param iterable which to handle * @param mapFn map function * @param element type of list * @param map result type * @return new list */ public static List map(Iterable iterable, Function mapFn) { Objects.requireNonNull(mapFn); if (iterable == null) { return new ArrayList<>(); } int capacity = 16; if (iterable instanceof List) { List list = (List) iterable; capacity = list.size(); } List result = new ArrayList<>(capacity); for (T t : iterable) { result.add(mapFn.apply(t)); } return result; } /** * Mapping a list of elements to another. * * @param iterable to be mapped * @param mapFn mapping function * @param type of elements applied to mapping function * @param type of elements returned by mapping function * @return mapping result */ public static List map(Iterable iterable, ObjIntFunction mapFn) { Objects.requireNonNull(mapFn); if (iterable == null) { return new ArrayList<>(); } int capacity = 16; if (iterable instanceof List) { List list = (List) iterable; capacity = list.size(); } List result = new ArrayList<>(capacity); int index = 0; for (T t : iterable) { result.add(mapFn.apply(t, index++)); } return result; } /** * Create a {@link Map} with key-value pairs. * * @param key type * @param value type * @return new HashMap */ public static Map mapOf() { return new HashMap<>(); } /** * Create a {@link Map} with key-value pairs. * * @param k1 the first key * @param v1 the first value * @param key type * @param value type * @return new HashMap */ public static Map mapOf(K k1, V v1) { Map map = new HashMap<>(); map.put(k1, v1); return map; } /** * Create a {@link Map} with key-value pairs. * * @param k1 the first key * @param v1 the first value * @param k2 the second key * @param v2 the second value * @param key type * @param value type * @return new HashMap */ public static Map mapOf(K k1, V v1, K k2, V v2) { Map map = new HashMap<>(); map.put(k1, v1); map.put(k2, v2); return map; } /** * Create a {@link Map} with key-value pairs. * * @param k1 the first key * @param v1 the first value * @param k2 the second key * @param v2 the second value * @param k3 the third key * @param v3 the third value * @param key type * @param value type * @return new HashMap */ public static Map mapOf(K k1, V v1, K k2, V v2, K k3, V v3) { Map map = new HashMap<>(); map.put(k1, v1); map.put(k2, v2); map.put(k3, v3); return map; } /** * Create a {@link Map} with key-value pairs. * * @param k1 the first key * @param v1 the first value * @param k2 the second key * @param v2 the second value * @param k3 the third key * @param v3 the third value * @param k4 the fourth key * @param v4 the fourth value * @param key type * @param value type * @return new HashMap */ public static Map mapOf(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { Map map = new HashMap<>(); map.put(k1, v1); map.put(k2, v2); map.put(k3, v3); map.put(k4, v4); return map; } /** * Create a {@link Map} with key-value pairs. * * @param k1 the first key * @param v1 the first value * @param k2 the second key * @param v2 the second value * @param k3 the third key * @param v3 the third value * @param k4 the fourth key * @param v4 the fourth value * @param k5 the fifth key * @param v5 the fifth value * @param key type * @param value type * @return new HashMap */ public static Map mapOf(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) { Map map = new HashMap<>(); map.put(k1, v1); map.put(k2, v2); map.put(k3, v3); map.put(k4, v4); map.put(k5, v5); return map; } /** * Create a {@link Map} with key-value pairs. * * @param k1 the first key * @param v1 the first value * @param k2 the second key * @param v2 the second value * @param k3 the third key * @param v3 the third value * @param k4 the fourth key * @param v4 the fourth value * @param k5 the fifth key * @param v5 the fifth value * @param k6 the sixth key * @param v6 the sixth value * @param key type * @param value type * @return new HashMap */ public static Map mapOf(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6) { Map map = new HashMap<>(); map.put(k1, v1); map.put(k2, v2); map.put(k3, v3); map.put(k4, v4); map.put(k5, v5); map.put(k6, v6); return map; } /** * Create a {@link Map} with key-value pairs. * * @param k1 the first key * @param v1 the first value * @param k2 the second key * @param v2 the second value * @param k3 the third key * @param v3 the third value * @param k4 the fourth key * @param v4 the fourth value * @param k5 the fifth key * @param v5 the fifth value * @param k6 the sixth key * @param v6 the sixth value * @param k7 the seventh key * @param v7 the seventh value * @param key type * @param value type * @return new HashMap */ public static Map mapOf(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7) { Map map = new HashMap<>(); map.put(k1, v1); map.put(k2, v2); map.put(k3, v3); map.put(k4, v4); map.put(k5, v5); map.put(k6, v6); map.put(k7, v7); return map; } /** * Create a {@link Map} with key-value pairs. * * @param k1 the first key * @param v1 the first value * @param k2 the second key * @param v2 the second value * @param k3 the third key * @param v3 the third value * @param k4 the fourth key * @param v4 the fourth value * @param k5 the fifth key * @param v5 the fifth value * @param k6 the sixth key * @param v6 the sixth value * @param k7 the seventh key * @param v7 the seventh value * @param k8 the eighth key * @param v8 the eighth value * @param key type * @param value type * @return new HashMap */ public static Map mapOf(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8) { Map map = new HashMap<>(); map.put(k1, v1); map.put(k2, v2); map.put(k3, v3); map.put(k4, v4); map.put(k5, v5); map.put(k6, v6); map.put(k7, v7); map.put(k8, v8); return map; } /** * Create a {@link Map} with key-value pairs. * * @param k1 the first key * @param v1 the first value * @param k2 the second key * @param v2 the second value * @param k3 the third key * @param v3 the third value * @param k4 the fourth key * @param v4 the fourth value * @param k5 the fifth key * @param v5 the fifth value * @param k6 the sixth key * @param v6 the sixth value * @param k7 the seventh key * @param v7 the seventh value * @param k8 the eighth key * @param v8 the eighth value * @param k9 the ninth key * @param v9 the ninth value * @param key type * @param value type * @return new HashMap */ public static Map mapOf(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9) { Map map = new HashMap<>(); map.put(k1, v1); map.put(k2, v2); map.put(k3, v3); map.put(k4, v4); map.put(k5, v5); map.put(k6, v6); map.put(k7, v7); map.put(k8, v8); map.put(k9, v9); return map; } /** * Create a {@link Map} with key-value pairs. * * @param k1 the first key * @param v1 the first value * @param k2 the second key * @param v2 the second value * @param k3 the third key * @param v3 the third value * @param k4 the fourth key * @param v4 the fourth value * @param k5 the fifth key * @param v5 the fifth value * @param k6 the sixth key * @param v6 the sixth value * @param k7 the seventh key * @param v7 the seventh value * @param k8 the eighth key * @param v8 the eighth value * @param k9 the ninth key * @param v9 the ninth value * @param k10 the tenth key * @param v10 the tenth value * @param key type * @param value type * @return new HashMap */ public static Map mapOf(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10) { Map map = new HashMap<>(); map.put(k1, v1); map.put(k2, v2); map.put(k3, v3); map.put(k4, v4); map.put(k5, v5); map.put(k6, v6); map.put(k7, v7); map.put(k8, v8); map.put(k9, v9); map.put(k10, v10); return map; } /** * Check if a string is empty or not. * * @param string to be checked * @return true if string is null, or it's length is 0 */ public static boolean isEmpty(String string) { return string == null || string.isEmpty(); } /** * Check if a {@link Map} is empty of not. * * @param map to be checked * @return true if map is null, or it has no any entries. */ public static boolean isEmpty(Map map) { return map == null || map.isEmpty(); } /** * Check if the collection is not empty. * * @param collection to be checked * @param type of elements * @return true if collection {@link #isEmpty(Collection)} is false */ public static boolean isNotEmpty(Collection collection) { return !isEmpty(collection); } /** * Check if a {@link Collection} is empty of not. * * @param c to be checked * @return true if map is null, or it has no any entries. */ public static boolean isEmpty(Collection c) { return c == null || c.isEmpty(); } /** * Check if a {@link Map} is not empty. * * @param map to be checked * @return true if map {@link #isEmpty(Map)} is false */ public static boolean isNotEmpty(Map map) { return !isEmpty(map); } /** * Check if the string is not empty. * * @param string to be checked * @return true if string {@link #isEmpty(String)} is false */ public static boolean isNotEmpty(String string) { return !isEmpty(string); } /** * Pads string on the left and right sides if it's shorter than length. * Padding characters are truncated if they can't be evenly divided by length. * * @param string The string to pad * @param length The padding length * @param chars The string used as padding * @return Padded string */ public static String pad(String string, int length, String chars) { if (length < 0) { throw new IllegalArgumentException("Argument length cannot be less than 0"); } string = defaultTo(string, ""); if (string.length() >= length) { return string; } char[] padChars = (isEmpty(chars) ? " " : chars).toCharArray(); StringBuilder sb = new StringBuilder(); int padLength = length - string.length(); int padHalf = padLength / 2; for (int i = 0; i < padHalf; i++) { sb.append(padChars[i % padChars.length]); } sb.append(string); for (int i = padHalf; i < padLength; i++) { sb.append(padChars[i % padChars.length]); } return sb.toString(); } /** * Pads string on the right side if it's shorter than length. * Padding characters are truncated if they exceed length. * * @param string The string to pad * @param length The padding length * @param chars The string used as padding * @return Padded string */ public static String padEnd(String string, int length, String chars) { if (length < 0) { throw new IllegalArgumentException("Argument length cannot be less than 0"); } string = defaultTo(string, ""); if (string.length() >= length) { return string; } char[] padChars = (isEmpty(chars) ? " " : chars).toCharArray(); StringBuilder sb = new StringBuilder(string); int padLength = length - string.length(); for (int i = 0; i < padLength; i++) { sb.append(padChars[i % padChars.length]); } return sb.toString(); } /** * Pads string on the left side if it's shorter than length. * Padding characters are truncated if they exceed length. * * @param string The string to pad * @param length The padding length * @param chars The string used as padding * @return Padded string */ public static String padStart(String string, int length, String chars) { if (length < 0) { throw new IllegalArgumentException("Argument length cannot be less than 0"); } string = defaultTo(string, ""); if (string.length() >= length) { return string; } char[] padChars = (isEmpty(chars) ? " " : chars).toCharArray(); StringBuilder sb = new StringBuilder(); int padLength = length - string.length(); for (int i = 0; i < padLength; i++) { sb.append(padChars[i % padChars.length]); } sb.append(string); return sb.toString(); } /** * Replace all substrings that match the given pattern with the result of the function. * For example: *

         * var pattern = Pattern.compile("\\{}");
         * System.out.println(replaceAll("a={} b={} c={}", pattern, i -> "{" + i + "}"));
         * 
* Output: *
         * a={0} b={1} c={2}
         * 
*

* If any of the arguments is {@code null}, the method will return the original string. * * @param string to be replaced * @param pattern to match * @param replacementGen to generate the replacement string by index * @return the replaced string */ public static String replaceAll(String string, Pattern pattern, IntFunction replacementGen) { if (string == null || pattern == null || replacementGen == null) { return string; } var matcher = pattern.matcher(string); boolean result = matcher.find(); if (result) { StringBuilder sb = new StringBuilder(); int start = 0; do { matcher.appendReplacement(sb, replacementGen.apply(start++)); result = matcher.find(); } while (result); matcher.appendTail(sb); return sb.toString(); } return string; } /** * Create an empty list stage. * * @param element type * @return list stage */ public static Seq empty() { return Seq.empty(); } /** * Create a stage from elements. * * @param args elements to be handled * @param type of elements * @return list stage */ @SafeVarargs public static Seq just(T... args) { return tConsumer -> { for (T t : args) { tConsumer.accept(t); } }; } /** * Handle a range. * * @param start range start - included * @param end range end - excluded * @return list stage */ public static Seq range(int start, int end) { return new Range(start, end)::forEach; } /** * Get the first element from {@link Iterable}. *

* Warning: When {@link Optional#empty()} is returned, uou cannot recognize * that the iterable is empty, or it's first element is null. * * @param iterable to be handled * @param type of the first element * @return {@link Optional} of the first element */ public static Optional first(Iterable iterable) { if (iterable == null) { return Optional.empty(); } if (iterable instanceof List) { List list = (List) iterable; return list.isEmpty() ? Optional.empty() : Optional.ofNullable(list.get(0)); } Iterator itr = iterable.iterator(); return itr.hasNext() ? Optional.ofNullable(itr.next()) : Optional.empty(); } /** * Alias for {@link #first(Iterable)}. * * @param iterable to be handled * @param type of the first element * @return {@link Optional} of the first element */ public static Optional head(Iterable iterable) { return first(iterable); } /** * Map elements to {@link Iterable}s in order and flat them into next stage. * * @param flatMapFn which map an element to an {@link Iterable} * @param flatten elements type * @return next stage */ public static List flatMap(Iterable iterable, Function> flatMapFn) { Objects.requireNonNull(flatMapFn); if (iterable == null) { return new ArrayList<>(); } ArrayList result = new ArrayList<>(); for (T t : iterable) { Iterable itr = flatMapFn.apply(t); if (itr != null) { itr.forEach(result::add); } } return result; } /** * Mapping {@link Map} values to another. * * @param map {@link Map} to be handled. * @param mapFn mapping function * @param type of {@link Map} key * @param type of {@link Map} value * @param type of mapping result * @return a new map */ public static Map mapValues(Map map, Function mapFn) { Objects.requireNonNull(mapFn); if (isEmpty(map)) { return new HashMap<>(); } Map result = new HashMap<>(); map.forEach((k, v) -> result.put(k, mapFn.apply(v))); return result; } /** * Mapping {@link Map} values to another. * * @param map {@link Map} to be handled. * @param mapFn mapping function which accept key as the second argument * @param type of {@link Map} key * @param type of {@link Map} value * @param type of mapping result * @return a new map */ public static Map mapValues(Map map, BiFunction mapFn) { Objects.requireNonNull(mapFn); if (isEmpty(map)) { return new HashMap<>(); } Map result = new HashMap<>(); map.forEach((k, v) -> result.put(k, mapFn.apply(v, k))); return result; } /** * Create a new {@link Map} with new keys, which are mapped from the old keys. * If two new keys of old keys are the same, the last reached entry would be discarded. * * @param map to be handled * @param mapFn mapping function * @param type of keys * @param type of values * @param type of mapped keys * @return new {@link Map} */ public static Map mapKeys(Map map, Function mapFn) { Objects.requireNonNull(mapFn); if (isEmpty(map)) { return new HashMap<>(); } Map result = new HashMap<>(); map.forEach((k, v) -> { K2 k2 = mapFn.apply(k); if (!result.containsKey(k2)) { result.put(k2, v); } }); return result; } /** * Create a new {@link Map} with new keys, which are mapped from the old keys. * If two new keys of different entries are equal, the last reached entry would be discarded. * * @param map to be handled * @param mapFn mapping function * @param type of keys * @param type of values * @param type of mapped keys * @return new {@link Map} */ public static Map mapKeys(Map map, BiFunction mapFn) { Objects.requireNonNull(mapFn); if (isEmpty(map)) { return new HashMap<>(); } Map result = new HashMap<>(); map.forEach((k, v) -> { K2 k2 = mapFn.apply(k, v); if (!result.containsKey(k2)) { result.put(k2, v); } }); return result; } /** * Create a new {@link Map} from {@link Iterable}. * The values are {@link Iterable} elements, * and the keys are computed from corresponding elements. * If two keys of different elements are equal, the first entry would be covered. * * @param iterable to be handled * @param toKey function mapping an element to it's key * @param type of iterable elements * @param type of key * @return new {@link Map} */ public static Map keyBy(Iterable iterable, Function toKey) { Objects.requireNonNull(toKey); if (iterable == null) { return new HashMap<>(); } Map result = new HashMap<>(); iterable.forEach(it -> result.computeIfAbsent(toKey.apply(it), k -> it)); return result; } /** * Create a new {@link Map} from {@link Iterable}. * The values are {@link List} of elements with the same key, * and the keys are computed from corresponding elements. * * @param iterable to be handled * @param toKey function mapping an element to it's key * @param type of iterable elements * @param type of key * @return new {@link Map} */ public static Map> groupBy(Iterable iterable, Function toKey) { Objects.requireNonNull(toKey); if (iterable == null) { return new HashMap<>(); } Map> result = new HashMap<>(); iterable.forEach(it -> result.computeIfAbsent(toKey.apply(it), k -> new ArrayList<>()).add(it)); return result; } /** * Order iterable into a list by element keys with specified direction. * * @param iterable to be ordered * @param toKey a function to get element key * @param direction order direction * @param type of elements * @param type of element keys * @return a list with sorted elements */ public static > List orderBy(Iterable iterable, Function toKey, Direction direction) { Objects.requireNonNull(toKey); Objects.requireNonNull(direction); if (iterable == null) { return new ArrayList<>(); } List list = $.listFrom(iterable.iterator()); Comparator comparator = direction == Direction.DESC ? descComparator(toKey) : ascComparator(toKey); list.sort(comparator); return list; } /** * Reducing {@link Iterable} to a value which is the accumulated result of running each element in * {@link Iterable} through reducer. * * @param iterable to be handled * @param initValue the init value * @param reducer reducer * @param type of elements * @param type of result * @return reducing result */ public static R reduce(Iterable iterable, R initValue, BiFunction reducer) { Objects.requireNonNull(reducer); if (iterable == null) { return initValue; } R result = initValue; for (T t : iterable) { result = reducer.apply(result, t); } return result; } /** * Reducing {@link Iterable} to a value which is the accumulated result of running each element in * {@link Iterable} through reducer. * * @param map to be handled * @param initValue the init value * @param reducer reducer * @param type of map keys * @param type of map values * @param type of result * @return reducing result */ public static R reduce(Map map, R initValue, Function3 reducer) { Objects.requireNonNull(reducer); if (map == null) { return initValue; } final Env1 env = new Env1<>(); env.t = initValue; map.forEach((k, v) -> env.t = reducer.apply(env.t, k, v)); return env.t; } private static class Env1 { T t; } /** * Reverse elements from an iterable into a list. * * @param iterable to be reversed * @param type of elements * @return a list of elements in reversed order */ public static List reverse(Iterable iterable) { ArrayList list = reduce(iterable, new ArrayList<>(), (li, it) -> { li.add(it); return li; }); int last = list.size() - 1; int half = list.size() / 2; for (int i = 0; i < half; i++) { T t1 = list.get(i); T t2 = list.get(last - i); list.set(last - i, t1); list.set(i, t2); } return list; } /** * Take the first n elements. * * @param iterable to be handled. * @param n count of element to be taken which should be greater than 0 * @param type of elements * @return a list of elements to be taken */ public static List take(Iterable iterable, int n) { if (n < 1) { throw new IllegalArgumentException("You should take at least one element."); } if (iterable == null) { return new ArrayList<>(); } ArrayList list = new ArrayList<>(); int i = 0; for (T t : iterable) { if (i < n) { list.add(t); i++; } else { break; } } return list; } /** * Take elements from iterable until the first element predicated to be false is found. * * @param iterable to be handled. * @param predicate a function to test elements * @param type of elements * @return a list of elements to be taken */ public static List takeWhile(Iterable iterable, Predicate predicate) { Objects.requireNonNull(predicate); if (iterable == null) { return new ArrayList<>(); } ArrayList list = new ArrayList<>(); for (T t : iterable) { if (predicate.test(t)) { list.add(t); } else { break; } } return list; } /** * Add all elements from iterable into a {@link Set}. * * @param iterable to be handled * @param type of elements * @return a set of elements from iterable */ public static Set toSet(Iterable iterable) { if (iterable == null) { return new HashSet<>(); } Set set = new HashSet<>(); iterable.forEach(set::add); return set; } /** * Iterates over elements of {@link Iterable} and each element will be consumed by handler in order. * * @param iterable to be handled * @param handler element handler * @param type of elements */ public static void forEach(Iterable iterable, Consumer handler) { if (iterable == null) { return; } iterable.forEach(handler); } /** * Iterates over elements of {@link Iterable} and each element will be consumed by handler in order. * The second argument of consumer is the index of correponding element. * * @param iterable to be handled * @param handler element handler * @param type of elements */ public static void forEach(Iterable iterable, ObjIntConsumer handler) { if (iterable == null) { return; } int i = 0; for (T it : iterable) { handler.accept(it, i++); } } /** * Iterates over elements of {@link Iterable} and remove the duplicated. * * @param iterable to be handled * @param type of elements * @return new {@link List} with unique elements */ public static List unique(Iterable iterable) { if (iterable == null) { return new ArrayList<>(); } List result = new ArrayList<>(); Set dedupSet = new HashSet<>(); for (T it : iterable) { if (!dedupSet.contains(it)) { dedupSet.add(it); result.add(it); } } return result; } /** * Iterates over elements of {@link Iterable} and remove the duplicated by keys. * * @param iterable to be handled * @param type of elements * @return new {@link List} with unique elements */ public static List uniqueBy(Iterable iterable, Function toKey) { Objects.requireNonNull(toKey); if (iterable == null) { return new ArrayList<>(); } List result = new ArrayList<>(); Set dedupSet = new HashSet<>(); for (T it : iterable) { K key = toKey.apply(it); if (!dedupSet.contains(key)) { dedupSet.add(key); result.add(it); } } return result; } /** * Iterates over elements of {@link Iterable} and remove the duplicated by keys. * The second argument of toKey function is the index of corresponding element. * * @param iterable to be handled * @param type of elements * @return new {@link List} with unique elements */ public static List uniqueBy(Iterable iterable, ObjIntFunction toKey) { Objects.requireNonNull(toKey); if (iterable == null) { return new ArrayList<>(); } List result = new ArrayList<>(); Set dedupSet = new HashSet<>(); int i = 0; for (T it : iterable) { K key = toKey.apply(it, i++); if (!dedupSet.contains(key)) { dedupSet.add(key); result.add(it); } } return result; } /** * {@link #zip(Iterable, Iterable, BiFunction) zip} two lists into a list of pairs. * * @param left first list * @param right second list * @param element type of the first list * @param element type of the second list * @return a list of pairs */ public static List> zip(Iterable left, Iterable right) { return zip(left, right, Pair::of); } /** * Combine the elements at the same position from two lists into one object in order. * * @param left first list * @param right second list * @param combineFn combine function. * @param element type of the first list * @param element type of the second list * @return a list of combined */ public static List zip(Iterable left, Iterable right, BiFunction combineFn) { Objects.requireNonNull(combineFn); List result = new ArrayList<>(); Iterator li = left == null ? EmptyIterator.create() : left.iterator(); Iterator ri = right == null ? EmptyIterator.create() : right.iterator(); while (true) { int state = 0; if (li.hasNext()) state += 1; if (ri.hasNext()) state += 2; switch (state) { case 0: return result; case 1: result.add(combineFn.apply(li.next(), null)); break; case 2: result.add(combineFn.apply(null, ri.next())); break; case 3: result.add(combineFn.apply(li.next(), ri.next())); break; default: throw new Unreachable(); } } } } private Dollar() throws IllegalAccessException { throw new IllegalAccessException("???"); } }