001/*-------------------------------------------------------------------------+ 002| | 003| Copyright 2005-2011 The ConQAT Project | 004| | 005| Licensed under the Apache License, Version 2.0 (the "License"); | 006| you may not use this file except in compliance with the License. | 007| You may obtain a copy of the License at | 008| | 009| http://www.apache.org/licenses/LICENSE-2.0 | 010| | 011| Unless required by applicable law or agreed to in writing, software | 012| distributed under the License is distributed on an "AS IS" BASIS, | 013| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 014| See the License for the specific language governing permissions and | 015| limitations under the License. | 016+-------------------------------------------------------------------------*/ 017package org.conqat.lib.commons.collections; 018 019import java.lang.reflect.Array; 020import java.util.ArrayDeque; 021import java.util.ArrayList; 022import java.util.Arrays; 023import java.util.Collection; 024import java.util.Collections; 025import java.util.Comparator; 026import java.util.Deque; 027import java.util.EnumSet; 028import java.util.HashMap; 029import java.util.HashSet; 030import java.util.Iterator; 031import java.util.List; 032import java.util.Map; 033import java.util.Objects; 034import java.util.Optional; 035import java.util.Random; 036import java.util.RandomAccess; 037import java.util.Set; 038import java.util.SortedMap; 039import java.util.SortedSet; 040import java.util.function.BiConsumer; 041import java.util.function.BiFunction; 042import java.util.function.Consumer; 043import java.util.function.Function; 044import java.util.function.Predicate; 045import java.util.function.Supplier; 046import java.util.stream.Collectors; 047 048import org.conqat.lib.commons.assertion.CCSMAssert; 049import org.conqat.lib.commons.string.StringUtils; 050 051/** 052 * This class offers utility methods for collections. In can be seen as an 053 * extension to {@link Collections}. 054 */ 055public class CollectionUtils { 056 057 /** Empty unmodifiable list. */ 058 private static final UnmodifiableList<?> EMPTY_LIST = new UnmodifiableList<>(Collections.emptyList()); 059 060 /** Empty unmodifiable map. */ 061 private static final UnmodifiableMap<?, ?> EMPTY_MAP = new UnmodifiableMap<>(Collections.emptyMap()); 062 063 /** Empty unmodifiable set. */ 064 private static final UnmodifiableSet<?> EMPTY_SET = new UnmodifiableSet<>(Collections.emptySet()); 065 066 /** Delimiter used in strings to separate list values. */ 067 public static final String MULTI_VALUE_DELIMITER = ","; 068 069 /** 070 * Create a hashed set from an array. 071 * 072 * @param <T> 073 * type 074 * @param elements 075 * elements in the set. 076 * @return the set. 077 * @see Arrays#asList(Object[]) 078 */ 079 @SafeVarargs 080 public static <T> HashSet<T> asHashSet(T... elements) { 081 HashSet<T> result = new HashSet<>(elements.length); 082 Collections.addAll(result, elements); 083 return result; 084 } 085 086 /** Creates a new unmodifiable {@link HashMap} based on given pairs. */ 087 @SafeVarargs 088 public static <K, V> UnmodifiableMap<K, V> asMap(Pair<K, V>... pairs) { 089 return asMap(new HashMap<>(), pairs); 090 } 091 092 /** 093 * Extends the given map with the pairs and returns an unmodifiable version. 094 */ 095 @SafeVarargs 096 public static <K, V> UnmodifiableMap<K, V> asMap(Map<K, V> baseMap, Pair<K, V>... pairs) { 097 for (Pair<K, V> pair : pairs) { 098 baseMap.put(pair.getFirst(), pair.getSecond()); 099 } 100 return asUnmodifiable(baseMap); 101 } 102 103 /** Creates an unmodifiable hash set from an array. */ 104 @SafeVarargs 105 public static <T> UnmodifiableSet<T> asUnmodifiableHashSet(T... elements) { 106 return new UnmodifiableSet<>(CollectionUtils.asHashSet(elements)); 107 } 108 109 /** 110 * Returns a new unmodifiable collection wrapping the given collection. This 111 * method is here to avoid retyping the generic argument for the collection 112 * class. 113 */ 114 public static <T> UnmodifiableCollection<T> asUnmodifiable(Collection<T> c) { 115 return new UnmodifiableCollection<>(c); 116 } 117 118 /** 119 * Returns a new unmodifiable list wrapping the given list. This method is here 120 * to avoid retyping the generic argument for the list class. 121 */ 122 public static <T> UnmodifiableList<T> asUnmodifiable(List<T> l) { 123 return new UnmodifiableList<>(l); 124 } 125 126 /** 127 * Returns a new unmodifiable map wrapping the given map. This method is here to 128 * avoid retyping the generic arguments for the map class. 129 */ 130 public static <S, T> UnmodifiableMap<S, T> asUnmodifiable(Map<S, T> m) { 131 return new UnmodifiableMap<>(m); 132 } 133 134 /** 135 * Returns a new unmodifiable set wrapping the given set. This method is here to 136 * avoid retyping the generic argument for the set class. 137 */ 138 public static <T> UnmodifiableSet<T> asUnmodifiable(Set<T> s) { 139 return new UnmodifiableSet<>(s); 140 } 141 142 /** 143 * Returns a new unmodifiable sorted map wrapping the given sorted map. This 144 * method is here to avoid retyping the generic arguments for the sorted map 145 * class. 146 */ 147 public static <S, T> UnmodifiableSortedMap<S, T> asUnmodifiable(SortedMap<S, T> m) { 148 return new UnmodifiableSortedMap<>(m); 149 } 150 151 /** 152 * Returns a new unmodifiable sorted set wrapping the given sorted set. This 153 * method is here to avoid retyping the generic argument for the sorted set 154 * class. 155 */ 156 public static <T> UnmodifiableSortedSet<T> asUnmodifiable(SortedSet<T> s) { 157 return new UnmodifiableSortedSet<>(s); 158 } 159 160 /** 161 * The way this method is defined allows to assign it to all parameterized 162 * types, i.e. both of the following statements are accepted by the compiler 163 * without warnings: 164 * 165 * <pre> 166 * UnmodifiableList<String> emptyList = CollectionUtils.emptyList(); 167 * 168 * UnmodifiableList<Date> emptyList = CollectionUtils.emptyList(); 169 * </pre> 170 * 171 * @return the empty list 172 */ 173 @SuppressWarnings("unchecked") 174 public static final <T> UnmodifiableList<T> emptyList() { 175 return (UnmodifiableList<T>) EMPTY_LIST; 176 } 177 178 /** Returns an empty map. See {@link #emptyList()} for further details. */ 179 @SuppressWarnings("unchecked") 180 public static final <S, T> UnmodifiableMap<S, T> emptyMap() { 181 return (UnmodifiableMap<S, T>) EMPTY_MAP; 182 } 183 184 /** Returns an empty set. See {@link #emptyList()} for further details. */ 185 @SuppressWarnings("unchecked") 186 public static final <T> UnmodifiableSet<T> emptySet() { 187 return (UnmodifiableSet<T>) EMPTY_SET; 188 } 189 190 /** 191 * Sorts the specified list into ascending order, according to the <i>natural 192 * ordering</i> of its elements. 193 * <p> 194 * All elements in the list must implement the Comparable interface. 195 * Furthermore, all elements in the list must be mutually comparable (that is, 196 * e1.compareTo(e2) must not throw a <code>ClassCastException</code> for any 197 * elements e1 and e2 in the list). 198 * <p> 199 * This method does not modify the original collection. 200 */ 201 public static <T extends Comparable<? super T>> ArrayList<T> sort(Collection<T> collection) { 202 ArrayList<T> list = new ArrayList<>(collection); 203 Collections.sort(list); 204 return list; 205 } 206 207 /** 208 * Returns a list that contains the elements of the specified list in reversed 209 * order. 210 * <p> 211 * This method does not modify the original collection. 212 */ 213 public static <T> ArrayList<T> reverse(Collection<T> list) { 214 ArrayList<T> reversed = new ArrayList<>(list); 215 Collections.reverse(reversed); 216 return reversed; 217 } 218 219 /** 220 * Returns all values, which occur multiple times in the list. 221 * <p> 222 * It doesn't tell you how often it occurs, just that it is more than once. 223 */ 224 public static <T> Set<T> getDuplicates(List<T> values) { 225 Set<T> duplicates = new HashSet<>(); 226 Set<T> temp = new HashSet<>(); 227 for (T key : values) { 228 if (!temp.add(key)) { 229 duplicates.add(key); 230 } 231 } 232 return duplicates; 233 } 234 235 /** 236 * Applies the mapper {@link Function} to all items in the collection and 237 * returns the resulting {@link List}. 238 * <p> 239 * This method does not modify the original collection. 240 */ 241 public static <T, R> List<R> map(Collection<T> list, Function<? super T, ? extends R> mapper) { 242 List<R> result = new ArrayList<>(list.size()); 243 for (T entry : list) { 244 result.add(mapper.apply(entry)); 245 } 246 return result; 247 } 248 249 /** 250 * Applies the mapper {@link Function} to all items in the collection and 251 * returns the resulting {@link Set} only containing distinct mapped values. 252 * <p> 253 * This method does not modify the original collection. 254 */ 255 public static <T, R> Set<R> mapToSet(Collection<T> list, Function<? super T, ? extends R> mapper) { 256 Set<R> result = new HashSet<>(); 257 for (T entry : list) { 258 result.add(mapper.apply(entry)); 259 } 260 return result; 261 } 262 263 /** 264 * Applies the key and value mapper {@link Function}s to all keys/values in the 265 * collection and returns the resulting {@link Map}. 266 * <p> 267 * This method does not modify the original collection. 268 */ 269 public static <K1, V1, K2, V2> Map<K2, V2> map(Map<K1, V1> map, Function<K1, ? extends K2> keyMapper, 270 Function<V1, ? extends V2> valueMapper) { 271 Map<K2, V2> result = new HashMap<>(map.size()); 272 map.forEach((key, value) -> result.put(keyMapper.apply(key), valueMapper.apply(value))); 273 return result; 274 } 275 276 /** 277 * Applies the mapper {@link Function} to all items in the array and returns the 278 * resulting {@link List}. 279 * <p> 280 * This method does not modify the original array. 281 */ 282 public static <T, R> List<R> map(T[] array, Function<? super T, ? extends R> mapper) { 283 return map(Arrays.asList(array), mapper); 284 } 285 286 /** 287 * Applies the mapper {@link Function} to all items in the collection, but only 288 * adds the result item to the return list if it is not already in the list. 289 * Returns the resulting {@link List}. 290 * <p> 291 * This method does not modify the original collection. 292 */ 293 public static <T, R> List<R> mapDistinct(Collection<T> list, Function<? super T, ? extends R> mapper) { 294 Set<R> encounteredItems = new HashSet<>(); 295 List<R> result = new ArrayList<>(); 296 for (T entry : list) { 297 R resultItem = mapper.apply(entry); 298 if (encounteredItems.add(resultItem)) { 299 result.add(resultItem); 300 } 301 } 302 return result; 303 } 304 305 /** 306 * Applies the mapper {@link FunctionWithException} to all items in the list and 307 * returns the resulting {@link List}. 308 * <p> 309 * This method does not modify the original collection. 310 * 311 * @throws E 312 * if the mapper function throws this exception for any of the 313 * elements of the original list. 314 */ 315 public static <T, R, E extends Exception> List<R> mapWithException(Collection<T> list, 316 FunctionWithException<? super T, ? extends R, ? extends E> mapper) throws E { 317 List<R> result = new ArrayList<>(list.size()); 318 for (T entry : list) { 319 result.add(mapper.apply(entry)); 320 } 321 return result; 322 } 323 324 /** Returns a new List containing only the elements at the given indices. */ 325 public static <T> ArrayList<T> getIndices(List<T> list, List<Integer> indices) { 326 ArrayList<T> filteredList = new ArrayList<>(); 327 for (int index : indices) { 328 filteredList.add(list.get(index)); 329 } 330 return filteredList; 331 } 332 333 /** 334 * Returns a new List containing all elements of the given list except for those 335 * with the given indices. 336 */ 337 public static <T> List<T> removeIndicesFrom(List<T> elements, Set<Integer> indices) { 338 List<T> result = new ArrayList<>(); 339 for (int i = 0; i < elements.size(); i++) { 340 if (!indices.contains(i)) { 341 result.add(elements.get(i)); 342 } 343 } 344 return result; 345 } 346 347 /** 348 * Returns the indices of null elements in the given list. The returned list is 349 * strictly ordered (returnedList.get(x) is greater than returnedList.get(x-1)). 350 */ 351 public static List<Integer> getNullIndices(List<?> list) { 352 List<Integer> nullIndices = new ArrayList<>(); 353 for (int i = 0; i < list.size(); i++) { 354 if (list.get(i) == null) { 355 nullIndices.add(i); 356 } 357 } 358 return nullIndices; 359 } 360 361 /** 362 * This interface is the same as {@link Supplier}, except it allows throwing a 363 * checked exception. 364 */ 365 @FunctionalInterface 366 public interface SupplierWithException<T, E extends Exception> { 367 368 /** 369 * Returns the supplied value. May throw a declared exception. 370 */ 371 T get() throws E; 372 } 373 374 /** 375 * This interface is the same as {@link Function}, except it allows throwing a 376 * checked exception. 377 */ 378 @FunctionalInterface 379 public interface FunctionWithException<T, R, E extends Exception> { 380 381 /** 382 * Applies the function to the given argument. May throw the declared exception. 383 */ 384 R apply(T t) throws E; 385 386 } 387 388 /** 389 * This interface is the same as {@link Consumer}, except it allows throwing a 390 * checked exception. 391 */ 392 @FunctionalInterface 393 public interface ConsumerWithException<T, E extends Exception> { 394 395 /** 396 * Performs this operation on the given argument. 397 * 398 * @param t 399 * the input argument 400 */ 401 void accept(T t) throws E; 402 403 } 404 405 /** 406 * This interface is the same as {@link Consumer}, except it allows throwing two 407 * checked exceptions. 408 */ 409 @FunctionalInterface 410 public interface ConsumerWithTwoExceptions<T, E1 extends Exception, E2 extends Exception> { 411 412 /** 413 * Performs this operation on the given argument. 414 * 415 * @param t 416 * the input argument 417 */ 418 void accept(T t) throws E1, E2; 419 420 } 421 422 /** 423 * This interface is the same as {@link BiConsumer}, except it allows throwing a 424 * checked exceptions. 425 */ 426 @FunctionalInterface 427 public interface BiConsumerWithException<S, T, E extends Exception> { 428 429 /** 430 * Performs this operation on the given argument. 431 * 432 * @param t 433 * the input argument 434 */ 435 void accept(S s, T t) throws E; 436 437 } 438 439 /** 440 * This interface is the same as {@link BiConsumer}, except it allows throwing 441 * two checked exceptions. 442 */ 443 @FunctionalInterface 444 public interface BiConsumerWithTwoExceptions<S, T, E1 extends Exception, E2 extends Exception> { 445 446 /** 447 * Performs this operation on the given argument. 448 * 449 * @param t 450 * the input argument 451 */ 452 void accept(S s, T t) throws E1, E2; 453 454 } 455 456 /** 457 * This interface is the same as {@link BiFunction}, except it allows throwing a 458 * checked exception. 459 */ 460 @FunctionalInterface 461 public interface BiFunctionWithException<T, U, R, E extends Exception> { 462 /** 463 * Returns the supplied value. May throw a declared exception. 464 */ 465 R apply(T t, U u) throws E; 466 } 467 468 /** 469 * Filters the collection by testing all items against the {@link Predicate} and 470 * returning a {@link List} of those for which it returns <code>true</code>. 471 * 472 * <p> 473 * This method does not modify the original collection. 474 */ 475 public static <T> List<T> filter(Collection<T> collection, Predicate<? super T> filter) { 476 ArrayList<T> result = new ArrayList<>(); 477 for (T entry : collection) { 478 if (filter.test(entry)) { 479 result.add(entry); 480 } 481 } 482 return result; 483 } 484 485 /** 486 * Filters the collection by testing all items against the given predicate and 487 * returning a {@link List} of those for which it returns <code>true</code>. 488 * Propagates checked exceptions of the given predicate. 489 * 490 * <p> 491 * This method does not modify the original collection. 492 */ 493 public static <T, E extends Exception> List<T> filterWithException(Collection<T> collection, 494 FunctionWithException<? super T, Boolean, E> filter) throws E { 495 ArrayList<T> result = new ArrayList<>(); 496 for (T entry : collection) { 497 if (filter.apply(entry)) { 498 result.add(entry); 499 } 500 } 501 return result; 502 } 503 504 /** 505 * Filters the collection by testing all items against the {@link Predicate} and 506 * returning a {@link Set} of those for which it returns <code>true</code>. 507 * 508 * <p> 509 * This method does not modify the original collection. 510 */ 511 public static <T> Set<T> filterToSet(Collection<T> collection, Predicate<? super T> filter) { 512 Set<T> result = new HashSet<>(); 513 for (T entry : collection) { 514 if (filter.test(entry)) { 515 result.add(entry); 516 } 517 } 518 return result; 519 } 520 521 /** 522 * Applies the mapper to all items in the list, for which the filter 523 * {@link Predicate} returns <code>true</code> and returns the results as a 524 * {@link List}. 525 * <p> 526 * This method does not modify the original collection. 527 */ 528 public static <T, R> List<R> filterAndMap(Collection<T> list, Predicate<? super T> filter, 529 Function<? super T, ? extends R> mapper) { 530 List<R> result = new ArrayList<>(); 531 for (T entry : list) { 532 if (filter.test(entry)) { 533 result.add(mapper.apply(entry)); 534 } 535 } 536 return result; 537 } 538 539 /** 540 * Returns a list that contains all elements of the specified list <B>except</B> 541 * the element at the specified index. Removes the index from the new List. 542 * <p> 543 * This method does not modify the original list. 544 */ 545 public static <T> List<T> remove(List<T> list, int index) { 546 ArrayList<T> result = new ArrayList<>(list); 547 result.remove(index); 548 return result; 549 } 550 551 /** 552 * Sorts the specified list according to the order induced by the specified 553 * comparator. 554 * <p> 555 * All elements in the list must implement the Comparable interface. 556 * Furthermore, all elements in the list must be mutually comparable (that is, 557 * e1.compareTo(e2) must not throw a <code>ClassCastException</code> for any 558 * elements e1 and e2 in the list). 559 * <p> 560 * This method does not modify the original collection. 561 */ 562 public static <T> List<T> sort(Collection<T> collection, Comparator<? super T> comparator) { 563 ArrayList<T> list = new ArrayList<>(collection); 564 list.sort(comparator); 565 return list; 566 } 567 568 /** Returns a sorted unmodifiable list for a collection. */ 569 public static <T extends Comparable<? super T>> UnmodifiableList<T> asSortedUnmodifiableList( 570 Collection<T> collection) { 571 return asUnmodifiable(sort(collection)); 572 } 573 574 /** 575 * Returns one object from an {@link Iterable} or <code>null</code> if the 576 * iterable is empty. 577 */ 578 public static <T> T getAny(Iterable<T> iterable) { 579 Iterator<T> iterator = iterable.iterator(); 580 if (!iterator.hasNext()) { 581 return null; 582 } 583 return iterator.next(); 584 } 585 586 /** 587 * Convert collection to array. This is a bit cleaner version of 588 * {@link Collection#toArray(Object[])}. 589 */ 590 @SuppressWarnings("unchecked") 591 public static <T> T[] toArray(Collection<? extends T> collection, Class<T> type) { 592 T[] result = (T[]) java.lang.reflect.Array.newInstance(type, collection.size()); 593 594 Iterator<? extends T> it = collection.iterator(); 595 for (int i = 0; i < collection.size(); i++) { 596 result[i] = it.next(); 597 } 598 599 return result; 600 } 601 602 /** 603 * Copy an array. This is a shortcut for {@link Arrays#copyOf(Object[], int)} 604 * that does not require to specify the length. 605 */ 606 public static <T> T[] copyArray(T[] original) { 607 return Arrays.copyOf(original, original.length); 608 } 609 610 /** 611 * Compute list of unordered pairs for all elements contained in a collection. 612 */ 613 public static <T> List<ImmutablePair<T, T>> computeUnorderedPairs(Collection<T> collection) { 614 List<T> elements = new ArrayList<>(collection); 615 List<ImmutablePair<T, T>> pairs = new ArrayList<>(); 616 617 int size = elements.size(); 618 for (int firstIndex = 0; firstIndex < size; firstIndex++) { 619 for (int secondIndex = firstIndex + 1; secondIndex < size; secondIndex++) { 620 pairs.add(new ImmutablePair<>(elements.get(firstIndex), elements.get(secondIndex))); 621 } 622 } 623 return pairs; 624 } 625 626 /** 627 * Returns the last element in list or <code>null</code>, if list is empty. 628 */ 629 @SuppressWarnings("unchecked") 630 public static <T> T getLast(List<T> list) { 631 if (list.isEmpty()) { 632 return null; 633 } 634 if (list instanceof Deque<?>) { 635 return ((Deque<T>) list).getLast(); 636 } 637 return list.get(list.size() - 1); 638 } 639 640 /** 641 * Returns the sublist of all but the first element in list or 642 * <code>null</code>, if list is empty. 643 */ 644 public static <T> List<T> getRest(List<T> list) { 645 if (list.isEmpty()) { 646 return null; 647 } 648 return list.subList(1, list.size()); 649 } 650 651 /** Sorts the pair list by first index. */ 652 public static <S extends Comparable<S>, T> void sortByFirst(PairList<S, T> list) { 653 sortByFirst(list, Comparator.naturalOrder()); 654 } 655 656 /** Sorts the pair list with the given comparator. */ 657 public static <S, T> void sortByFirst(PairList<S, T> list, Comparator<S> comparator) { 658 SortableDataUtils.sort(new ISortableData() { 659 660 @Override 661 public void swap(int i, int j) { 662 list.swapEntries(i, j); 663 } 664 665 @Override 666 public int size() { 667 return list.size(); 668 } 669 670 @Override 671 public boolean isLess(int i, int j) { 672 return comparator.compare(list.getFirst(i), list.getFirst(j)) < 0; 673 } 674 }); 675 } 676 677 /** 678 * Returns a list implementation that allows for efficient random access. 679 * 680 * If the passed collection already supports random access, it gets returned 681 * directly. Otherwise a list that supports random access is returned with the 682 * same content as the passed list. 683 */ 684 public static <T> List<T> asRandomAccessList(Collection<T> list) { 685 // It is not guaranteed that implementations of RandomAccess also 686 // implement List. Hence, we check for both. 687 if (list instanceof List<?> && list instanceof RandomAccess) { 688 return (List<T>) list; 689 } 690 691 return new ArrayList<>(list); 692 } 693 694 @SafeVarargs 695 private static <T, C extends Collection<T>> C unionCollection(Supplier<C> collectionSupplier, 696 Collection<T> collection1, Collection<T>... furtherCollections) { 697 C result = collectionSupplier.get(); 698 if (collection1 != null) { 699 result.addAll(collection1); 700 } 701 for (Collection<T> collection : furtherCollections) { 702 if (collection != null) { 703 result.addAll(collection); 704 } 705 } 706 return result; 707 } 708 709 /** 710 * Return a set containing the union of all provided collections. We use a 711 * {@link HashSet}, i.e. the elements should support hashing. 712 * 713 * We use two separate arguments to ensure on the interface level that at least 714 * one collection is provided. This is transparent for the caller. 715 * 716 * All arguments can be null. The result will always be non-null and will be an 717 * empty set if all arguments are null. 718 */ 719 @SafeVarargs 720 public static <T> HashSet<T> unionSet(Collection<T> collection1, Collection<T>... furtherCollections) { 721 return unionCollection(HashSet::new, collection1, furtherCollections); 722 } 723 724 /** 725 * Return a set containing the union of all provided {@link EnumSet}s. 726 * 727 * We use two separate arguments to ensure on the interface level that at least 728 * one collection is provided. This is transparent for the caller. 729 * 730 * None of the arguments may be null. 731 */ 732 @SafeVarargs 733 public static <T extends Enum<T>> EnumSet<T> enumUnionSet(EnumSet<T> initialSet, EnumSet<T>... otherSets) { 734 EnumSet<T> union = EnumSet.copyOf(initialSet); 735 for (EnumSet<T> other : otherSets) { 736 union.addAll(other); 737 } 738 return union; 739 } 740 741 /** 742 * Return a set containing the union of all provided collections. We use a 743 * {@link ArrayList} and the result preserves duplicates between and within the 744 * collections. 745 * 746 * We use two separate arguments to ensure on the interface level that at least 747 * one collection is provided. This is transparent for the caller. 748 * 749 * All arguments can be null. The result will always be non-null and will be an 750 * empty set if all arguments are null. 751 */ 752 @SafeVarargs 753 public static <T> ArrayList<T> unionList(Collection<T> collection1, Collection<T>... furtherCollections) { 754 return unionCollection(ArrayList::new, collection1, furtherCollections); 755 } 756 757 /** 758 * Return a set containing the union of all elements of the provided sets. We 759 * use a {@link HashSet}, i.e. the elements should support hashing. 760 */ 761 public static <T> HashSet<T> unionSetAll(Collection<? extends Collection<T>> sets) { 762 HashSet<T> result = new HashSet<>(); 763 for (Collection<T> set : sets) { 764 result.addAll(set); 765 } 766 return result; 767 } 768 769 /** 770 * Creates a new set only containing those elements of the given collection that 771 * are not in elementsToRemove. Substracts elementsToRemove from collection. 772 * Both collections may be <code>null</code>. 773 */ 774 public static <T> Set<T> subtract(Collection<T> collection, Collection<T> elementsToRemove) { 775 Set<T> result = new HashSet<>(); 776 if (collection != null) { 777 result.addAll(collection); 778 } 779 if (elementsToRemove != null) { 780 result.removeAll(elementsToRemove); 781 } 782 return result; 783 } 784 785 /** 786 * Adds all elements of collection2 to collection1. collection2 may be 787 * <code>null</code>, in which case nothing happens. 788 */ 789 public static <T> void addAllSafe(Collection<T> collection1, Collection<T> collection2) { 790 if (collection2 != null) { 791 collection1.addAll(collection2); 792 } 793 } 794 795 /** 796 * Return a set containing the intersection of all provided collections. We use 797 * a {@link HashSet}, i.e. the elements should support hashing. 798 * 799 * We use two separate arguments to ensure on the interface level that at least 800 * one collection is provided. This is transparent for the caller. 801 */ 802 @SafeVarargs 803 public static <T> HashSet<T> intersectionSet(Collection<T> collection1, Collection<T>... furtherCollections) { 804 HashSet<T> result = new HashSet<>(collection1); 805 for (Collection<T> collection : furtherCollections) { 806 if (collection instanceof Set) { 807 result.retainAll(collection); 808 } else { 809 // if the collection is not already a set, it will be 810 // significantly faster to first build a set, to speed up the 811 // containment query in the following call. 812 result.retainAll(new HashSet<>(collection)); 813 } 814 } 815 return result; 816 } 817 818 /** 819 * Returns the set-theoretic difference between the first and the additional 820 * collections, i.e. a set containing all elements that occur in the first, but 821 * not in any of the other collections. We use a {@link HashSet}, so the 822 * elements should support hashing. 823 */ 824 @SafeVarargs 825 public static <T> HashSet<T> differenceSet(Collection<T> collection1, 826 Collection<? extends T>... furtherCollections) { 827 HashSet<T> result = new HashSet<>(collection1); 828 for (Collection<? extends T> collection : furtherCollections) { 829 if (collection instanceof Set) { 830 result.removeAll(collection); 831 } else { 832 // if the collection is not already a set, it will be 833 // significantly faster to first build a set, to speed up the 834 // containment query in the following call. 835 result.removeAll(new HashSet<>(collection)); 836 } 837 } 838 return result; 839 } 840 841 /** Checks whether collection is null or empty */ 842 public static boolean isNullOrEmpty(Collection<?> collection) { 843 return collection == null || collection.isEmpty(); 844 } 845 846 /** Checks whether map is null or empty */ 847 public static boolean isNullOrEmpty(Map<?, ?> map) { 848 return map == null || map.isEmpty(); 849 } 850 851 /** 852 * Truncates the given list by removing elements from the end such that 853 * numElements entries remain. If the list has less than numElements entries, it 854 * remains unchanged. Thus, this method ensures that the size of the list is <= 855 * numElements. 856 */ 857 public static void truncateEnd(List<?> list, int numElements) { 858 if (list.size() > numElements) { 859 list.subList(numElements, list.size()).clear(); 860 } 861 } 862 863 /** 864 * Divides the given set randomly but, as far as possible, evenly into k subsets 865 * of equal size, i.e., if set.size() is not a multiple of k, (k-(set.size() 866 * modulo k)) of the resulting sets have one element less. 867 * 868 * @param <S> 869 * must support hashing. 870 */ 871 public static <S> List<Set<S>> divideEvenlyIntoKSubsets(Set<S> set, int k, Random rnd) { 872 int n = set.size(); 873 CCSMAssert.isTrue(n >= k, "The size of the set must be at least k"); 874 CCSMAssert.isTrue(k > 0, "k must be greater than 0"); 875 876 List<S> shuffled = new ArrayList<>(set); 877 Collections.shuffle(shuffled, rnd); 878 879 List<Set<S>> result = new ArrayList<>(); 880 881 // we can fill (n%k) buckets with (n/k+1) elements 882 int subsetSize = n / k + 1; 883 for (int i = 0; i < n % k; i++) { 884 result.add(new HashSet<>(shuffled.subList(i * subsetSize, (i + 1) * subsetSize))); 885 } 886 887 int offset = n % k * subsetSize; 888 889 // fill the rest of the buckets with (n/k) elements 890 subsetSize = n / k; 891 for (int i = 0; i < k - n % k; i++) { 892 result.add(new HashSet<>(shuffled.subList(offset + i * subsetSize, offset + (i + 1) * subsetSize))); 893 } 894 895 return result; 896 } 897 898 /** Obtain all permutations of the provided elements. */ 899 public static <T> List<List<T>> getAllPermutations(@SuppressWarnings("unchecked") T... elements) { 900 List<List<T>> result = new ArrayList<>(); 901 permute(Arrays.asList(elements), 0, result); 902 return result; 903 } 904 905 /** Recursively creates permutations. */ 906 private static <T> void permute(List<T> list, int index, List<List<T>> result) { 907 for (int i = index; i < list.size(); i++) { 908 Collections.swap(list, i, index); 909 permute(list, index + 1, result); 910 Collections.swap(list, index, i); 911 } 912 if (index == list.size() - 1) { 913 result.add(new ArrayList<>(list)); 914 } 915 } 916 917 /** 918 * Returns the power set of the given input list. Note that elements are treated 919 * as unique, i.e. we do not really use set semantics here. Also note that the 920 * returned list has 2^n elements for n input elements, so the input list should 921 * not be too large. 922 */ 923 public static <T> List<List<T>> getPowerSet(List<T> input) { 924 return getPowerSet(input, 0); 925 } 926 927 /** 928 * Returns the power set of the given input list, only considering elements at 929 * or after index <code>start</code>. 930 */ 931 private static <T> List<List<T>> getPowerSet(List<T> input, int start) { 932 ArrayList<List<T>> result = new ArrayList<>(); 933 if (start >= input.size()) { 934 result.add(new ArrayList<>()); 935 } else { 936 T element = input.get(start); 937 for (List<T> list : getPowerSet(input, start + 1)) { 938 List<T> copy = new ArrayList<>(); 939 copy.add(element); 940 copy.addAll(list); 941 942 result.add(list); 943 result.add(copy); 944 } 945 } 946 return result; 947 } 948 949 /** 950 * Returns the input list, or {@link #emptyList()} if the input is null. 951 */ 952 public static <T> List<T> emptyIfNull(List<T> input) { 953 if (input == null) { 954 return emptyList(); 955 } 956 return input; 957 } 958 959 /** 960 * Returns the input map, or uses the given supplier to create a new one. 961 */ 962 public static <K, V, M extends Map<K, V>> M emptyIfNull(M input, Supplier<M> supplier) { 963 return Optional.ofNullable(input).orElseGet(supplier); 964 } 965 966 /** Removes an element from the array and returns the new array. */ 967 @SuppressWarnings("unchecked") 968 public static <T> T[] removeElementFromArray(T element, T[] array) { 969 ArrayList<T> result = new ArrayList<>(Arrays.asList(array)); 970 result.remove(element); 971 return toArray(result, (Class<T>) element.getClass()); 972 } 973 974 /** 975 * Returns a new list containing only the non-null elements of the given list. 976 */ 977 public static <T> List<T> filterNullEntries(List<T> list) { 978 return filter(list, Objects::nonNull); 979 } 980 981 /** 982 * Returns a new list containing only the non-null elements of the given array. 983 */ 984 public static <T> List<T> filterNullEntries(T[] array) { 985 return filterNullEntries(Arrays.asList(array)); 986 } 987 988 /** 989 * Concatenate two arrays to a new one. See also: 990 * http://stackoverflow.com/a/80503/205903 991 */ 992 public static <T> T[] concatenateArrays(T[] a, T[] b) { 993 int length1 = a.length; 994 int length2 = b.length; 995 996 @SuppressWarnings("unchecked") 997 T[] newArray = (T[]) Array.newInstance(a.getClass().getComponentType(), length1 + length2); 998 System.arraycopy(a, 0, newArray, 0, length1); 999 System.arraycopy(b, 0, newArray, length1, length2); 1000 1001 return newArray; 1002 } 1003 1004 /** Returns if any element in the collection matches the predicate. */ 1005 public static <T> boolean anyMatch(Collection<? extends T> collection, Predicate<T> predicate) { 1006 for (T element : collection) { 1007 if (predicate.test(element)) { 1008 return true; 1009 } 1010 } 1011 return false; 1012 } 1013 1014 /** Returns if all elements in the collection match the predicate. */ 1015 public static <T> boolean allMatch(Collection<? extends T> collection, Predicate<T> predicate) { 1016 for (T element : collection) { 1017 if (!predicate.test(element)) { 1018 return false; 1019 } 1020 } 1021 return true; 1022 } 1023 1024 /** 1025 * Sorts the given collection topologically. The given 1026 * <code>getSuccessors</code> function must establish an order on the elements 1027 * of the collection (more details below). 1028 * 1029 * The sorting is stable if the stream() iterator on the given collection is 1030 * stable. 1031 * 1032 * The result of this function is a <code>Pair</code>. The first item of the 1033 * pair contains the sorted collection as a list. The second item contains a set 1034 * of elements that could not be fit into the topological order (in case there 1035 * are cycles in the partial order). This second item is empty if there are no 1036 * cycles. Elements of the second item are not contained in the sorted list, so 1037 * callers should check whether the second item is empty. 1038 * 1039 * Direction of the sorting: if <code>getSuccessors(A).contains(B)</code>, then 1040 * <code>A</code> will be before <code>B</code> in the sorted list. 1041 * 1042 * Details on the order established by <code>getSuccessors</code>: In 1043 * literature, this should be a partial order, but we don't seem to require the 1044 * properties of partial orders (reflexivity, transitivity, antisymmetry). We 1045 * just need an order relation that maps each element to its direct successors. 1046 * In fact this method will be faster when the order relation is smaller, so 1047 * forget reflexivity and transitivity. Antisymmetry would be nice (otherwise 1048 * you'll get a cycle for sure). 1049 * 1050 * If <code>getSuccessors</code> returns null for an element, we will treat this 1051 * as if it was an empty collection. 1052 * 1053 * @param collection 1054 * the collection to be sorted 1055 * @param getSuccessors 1056 * the order relation (described above) 1057 * @return a topologically sorted collection 1058 */ 1059 public static <T> Pair<List<T>, List<T>> topSort(Collection<T> collection, 1060 Function<T, Collection<T>> getSuccessors) { 1061 UnmodifiableSet<T> inputSet = CollectionUtils.asUnmodifiable(new HashSet<>(collection)); 1062 // counts how many unhandled predecessors an element has 1063 // elements not in this list have no unhandled predecessors 1064 CounterSet<T> numUnhandledPredecessors = new CounterSet<>(); 1065 for (T element : collection) { 1066 Collection<? extends T> successors = getSuccessors.apply(element); 1067 if (successors != null) { 1068 successors.stream().filter(inputSet::contains).forEach(numUnhandledPredecessors::inc); 1069 } 1070 } 1071 // elements that have no predecessors (they can be inserted in the 1072 // sorted list) 1073 Deque<T> freeElements = collection.stream().filter(element -> !numUnhandledPredecessors.contains(element)) 1074 .collect(Collectors.toCollection(ArrayDeque::new)); 1075 List<T> result = new ArrayList<>(collection.size()); 1076 while (!freeElements.isEmpty()) { 1077 T element = freeElements.remove(); 1078 result.add(element); 1079 handleTopSortElementSuccessors(getSuccessors.apply(element), numUnhandledPredecessors, freeElements, 1080 inputSet); 1081 } 1082 // need to sort for stable result 1083 List<T> cycle = numUnhandledPredecessors.getKeys().stream().sorted().collect(Collectors.toList()); 1084 return new Pair<>(result, cycle); 1085 } 1086 1087 /** 1088 * This method is part of the {@link #topSort(Collection, Function)} algorithm. 1089 * It handles the successors of one element that has been inserted in the 1090 * top-sorted list. 1091 * 1092 * This method considers only successors that are part of the given filterSet. 1093 * For each of these successors, it decreases the numUnhandledPredecessors entry 1094 * by one. If a successor has no predecessors any more after the decrease, it is 1095 * added to the given freeElements. 1096 */ 1097 private static <T> void handleTopSortElementSuccessors(Collection<? extends T> successors, 1098 CounterSet<T> numUnhandledPredecessors, Deque<T> freeElements, UnmodifiableSet<T> filterSet) { 1099 if (successors != null) { 1100 successors.stream().filter(filterSet::contains).forEach(successor -> { 1101 numUnhandledPredecessors.inc(successor, -1); 1102 if (numUnhandledPredecessors.getValue(successor) <= 0) { 1103 freeElements.add(successor); 1104 numUnhandledPredecessors.remove(successor); 1105 } 1106 }); 1107 } 1108 } 1109 1110 /** 1111 * Sorts the given collection topologically, even if it contains cycles 1112 * (deterministically random elements in the cycle are removed). The given 1113 * <code>getSuccessors</code> function must establish an order on the elements 1114 * of the collection (more details below). The given 1115 * <code>getPredecessors</code> function must establish the reverse order of 1116 * <code>getSuccessors</code>. 1117 * 1118 * 1119 * The sorting is stable if the stream() iterator on the given collection is 1120 * stable. 1121 * 1122 * The result of this function is a <code>Pair</code>. The first item of the 1123 * pair contains the sorted collection as a list. The second item contains a 1124 * list of cycle elements that were removed to enable topological sorting. 1125 * 1126 * Direction of the sorting: if <code>getSuccessors(A).contains(B)</code>, then 1127 * <code>A</code> will be before <code>B</code> in the sorted list. 1128 * 1129 * For detail requirements on <code>getSuccessors</code> and 1130 * <code>getPredecessors</code>, see {@link #topSort(Collection, Function)}. 1131 * 1132 * @param collection 1133 * the collection to be sorted 1134 * @param getSuccessors 1135 * the order relation (described above) 1136 * @return a topologically sorted collection 1137 */ 1138 public static <T> Pair<List<T>, Set<T>> topSortRemoveCycles(Collection<T> collection, 1139 Function<T, Collection<T>> getSuccessors, Function<T, Collection<T>> getPredecessors) { 1140 // First remove all nodes that have trivial cycle references to themselves 1141 Set<T> removedCycleElements = collection.stream().filter(node -> { 1142 Collection<T> successors = getSuccessors.apply(node); 1143 return successors != null && successors.contains(node); 1144 }).collect(Collectors.toSet()); 1145 List<T> reducedCollection = new ArrayList<>(collection); 1146 reducedCollection.removeIf(removedCycleElements::contains); 1147 1148 Pair<List<T>, List<T>> topSorted = topSort(reducedCollection, getSuccessors); 1149 if (topSorted.getSecond().isEmpty()) { 1150 return new Pair<>(topSorted.getFirst(), removedCycleElements); 1151 } 1152 1153 /* 1154 * Implementation idea: After remove non-cycle vertices alternatingly from "top" 1155 * and "bottom" and store them for the result. From the resulting cycle, remove 1156 * one vertex and repeat. 1157 */ 1158 List<T> tailElements = new ArrayList<>(); 1159 List<T> headElements = topSorted.getFirst(); 1160 List<T> cycle = topSorted.getSecond(); 1161 while (!cycle.isEmpty()) { 1162 Pair<List<T>, List<T>> inverseTopSortedCycle = topSort(cycle, getPredecessors); 1163 tailElements.addAll(inverseTopSortedCycle.getFirst()); 1164 cycle = inverseTopSortedCycle.getSecond(); 1165 if (!cycle.isEmpty()) { 1166 removedCycleElements.add(cycle.remove(cycle.size() - 1)); 1167 } 1168 Pair<List<T>, List<T>> topSortedCycle = topSort(cycle, getSuccessors); 1169 headElements.addAll(topSortedCycle.getFirst()); 1170 cycle = topSortedCycle.getSecond(); 1171 } 1172 headElements.addAll(reverse(tailElements)); 1173 return new Pair<>(headElements, removedCycleElements); 1174 } 1175 1176 /** 1177 * Maps all entries of the given Collection to their string representations. 1178 * This method always returns a list. The order of elements in the returned list 1179 * corresponds to the order of element returned by input.stream(), i.e., if 1180 * input is a List then the order is stable, if input is a set then the order is 1181 * random. 1182 */ 1183 public static List<String> toStringSet(Collection<?> input) { 1184 return input.stream().map(Object::toString).collect(Collectors.toList()); 1185 } 1186 1187 /** 1188 * Returns a {@link Comparator} that compares lists. Shorter lists are 1189 * considered "smaller" than longer lists. If lists have the same length, 1190 * elements are compared using their compareTo methods until one is found that 1191 * is does not return 0 when compared to its counterpart. If list lengths are 1192 * equal and all elements return 0 on comparison, the returned 1193 * {@link Comparator} returns 0. 1194 */ 1195 public static <L extends List<T>, T extends Comparable<T>> Comparator<L> getListComparator() { 1196 return getListComparator(T::compareTo); 1197 } 1198 1199 /** 1200 * Returns a {@link Comparator} that compares lists. Shorter lists are 1201 * considered "smaller" than longer lists. If lists have the same length, 1202 * elements are compared using the given elementComparator until one is found 1203 * that is does not return 0 when compared to its counterpart. If list lengths 1204 * are equal and all elements return 0 on comparison, the returned 1205 * {@link Comparator} returns 0. 1206 */ 1207 public static <L extends List<T>, T> Comparator<L> getListComparator(Comparator<T> elementComparator) { 1208 return (o1, o2) -> { 1209 if (o1.size() != o2.size()) { 1210 return o1.size() - o2.size(); 1211 } 1212 for (int i = 0; i < o1.size(); i++) { 1213 int currentComparison = elementComparator.compare(o1.get(i), o2.get(i)); 1214 if (currentComparison != 0) { 1215 return currentComparison; 1216 } 1217 } 1218 return 0; 1219 }; 1220 } 1221 1222 /** 1223 * Returns a {@link Comparator} that compares {@link Pair}s of 1224 * {@link Comparable}s. First compares the first elements and if their 1225 * comparison returns 0, compares the second elements. If their comparison also 1226 * return 0, this {@link Comparator} returns 0. 1227 */ 1228 public static <P extends Pair<T, S>, T extends Comparable<T>, S extends Comparable<S>> Comparator<P> getPairComparator() { 1229 return (o1, o2) -> { 1230 int firstComparison = o1.getFirst().compareTo(o2.getFirst()); 1231 if (firstComparison != 0) { 1232 return firstComparison; 1233 } 1234 return o1.getSecond().compareTo(o2.getSecond()); 1235 }; 1236 } 1237 1238 /** Returns an empty {@link Consumer} that does nothing. */ 1239 public static <T> Consumer<T> emptyConsumer() { 1240 return x -> { 1241 // empty 1242 }; 1243 } 1244 1245 /** 1246 * Splits a {@link String} representing a list of values to a list of lines and 1247 * forwards it to {@link CollectionUtils#parseMultiValueStringToList(List)}. 1248 */ 1249 public static List<String> parseMultiValueStringToList(String valueList) { 1250 List<String> lines = StringUtils.splitWithEscapeCharacter(valueList, "\\n"); 1251 return parseMultiValueStringToList(lines); 1252 } 1253 1254 /** 1255 * Parses a {@link List} of {@link String} representing lines of values to a 1256 * list of the single values. The value entries must be separated by 1257 * {@value #MULTI_VALUE_DELIMITER}. 1258 */ 1259 public static List<String> parseMultiValueStringToList(List<String> valueListLines) { 1260 List<String> results = new ArrayList<>(); 1261 for (String line : valueListLines) { 1262 List<String> result = StringUtils.splitWithEscapeCharacter(line, MULTI_VALUE_DELIMITER); 1263 for (String value : result) { 1264 if (StringUtils.isEmpty(value)) { 1265 throw new IllegalArgumentException( 1266 "Found duplicate comma (empty value) in list: " + valueListLines); 1267 } 1268 } 1269 results.addAll(result); 1270 } 1271 return results; 1272 } 1273 1274 /** 1275 * Creates a {@link List} that holds the combination of the values of two 1276 * collections. 1277 * 1278 * @see #combine(Collection, Collection, Collection, BiFunction) 1279 */ 1280 public static <T1, T2, RESULT> List<RESULT> combine(Collection<T1> firstValues, Collection<T2> secondValues, 1281 BiFunction<T1, T2, RESULT> combineFunction) { 1282 List<RESULT> resultList = new ArrayList<>(firstValues.size()); 1283 return combine(firstValues, secondValues, resultList, combineFunction); 1284 } 1285 1286 /** 1287 * Creates a {@link Collection} that holds the combination of the values of two 1288 * collections. 1289 * 1290 * Both collections must be of the same size. The order of insertion into the 1291 * new {@link Collection} is determined by the order imposed by the collections' 1292 * iterators. 1293 */ 1294 public static <T1, T2, RESULT, COLLECTION extends Collection<RESULT>> COLLECTION combine(Collection<T1> firstValues, 1295 Collection<T2> secondValues, COLLECTION resultCollection, BiFunction<T1, T2, RESULT> combineFunction) { 1296 CCSMAssert.isTrue(firstValues.size() == secondValues.size(), "Can only combine collections of the same size."); 1297 Iterator<T1> firstIterator = firstValues.iterator(); 1298 Iterator<T2> secondIterator = secondValues.iterator(); 1299 while (firstIterator.hasNext()) { 1300 resultCollection.add(combineFunction.apply(firstIterator.next(), secondIterator.next())); 1301 } 1302 return resultCollection; 1303 } 1304 1305 /** 1306 * Applies the function to the values of both collections at the same index. 1307 * 1308 * Both collections must be of the same size. 1309 */ 1310 public static <T1, T2> void forEach(Collection<T1> firstValues, Collection<T2> secondValues, 1311 BiConsumer<T1, T2> combineFunction) { 1312 CCSMAssert.isTrue(firstValues.size() == secondValues.size(), "Can only combine collections of the same size."); 1313 Iterator<T1> firstIterator = firstValues.iterator(); 1314 Iterator<T2> secondIterator = secondValues.iterator(); 1315 while (firstIterator.hasNext()) { 1316 combineFunction.accept(firstIterator.next(), secondIterator.next()); 1317 } 1318 } 1319 1320 /** 1321 * Applies the function to the values of both collections at the same index. 1322 * 1323 * Both collections must be of the same size. 1324 */ 1325 public static <T1, T2, E extends Exception> void forEachWithException(Collection<T1> firstValues, 1326 Collection<T2> secondValues, BiConsumerWithException<? super T1, ? super T2, E> combineFunction) throws E { 1327 CCSMAssert.isTrue(firstValues.size() == secondValues.size(), "Can only combine collections of the same size."); 1328 Iterator<T1> firstIterator = firstValues.iterator(); 1329 Iterator<T2> secondIterator = secondValues.iterator(); 1330 while (firstIterator.hasNext()) { 1331 combineFunction.accept(firstIterator.next(), secondIterator.next()); 1332 } 1333 } 1334 1335 /** 1336 * Returns the element index of the first element in the list that matches the 1337 * given predicate. Returns -1 if no element matches the predicate. 1338 */ 1339 public static <T> int indexOfFirstMatch(List<T> list, Predicate<T> predicate) { 1340 int listSize = list.size(); 1341 for (int i = 0; i < listSize; i++) { 1342 if (predicate.test(list.get(i))) { 1343 return i; 1344 } 1345 } 1346 return -1; 1347 } 1348 1349 /** 1350 * Returns a map that maps each element of the first list to the corresponding 1351 * (by index) element of the second list. The lists must have the same size. 1352 */ 1353 public static <K, V> Map<K, V> zipAsMap(List<K> first, List<V> second) { 1354 CCSMAssert.isTrue(first.size() == second.size(), 1355 "Need the same number of elements in the given lists. Found " + first.size() + " / " + second.size()); 1356 Map<K, V> resultMap = new HashMap<>(); 1357 for (int i = 0; i < first.size(); i++) { 1358 resultMap.put(first.get(i), second.get(i)); 1359 } 1360 return resultMap; 1361 } 1362 1363 /** 1364 * Wrapper for {@link List#subList(int, int)} with only a from parameter. 1365 * 1366 * Returns a view of the portion of this list between the specified 1367 * <tt>fromIndex</tt>, inclusive, and the end of the list. The returned list is 1368 * backed by this list, so non-structural changes in the returned list are 1369 * reflected in this list, and vice-versa. 1370 * 1371 * @param fromIndex 1372 * low endpoint (inclusive) of the subList 1373 * @return a view of the specified range within this list 1374 * @throws IndexOutOfBoundsException 1375 * for an illegal endpoint index value 1376 * (<tt>fromIndex < 0 || fromIndex > size</tt>) 1377 */ 1378 public static <T> List<T> subListFrom(List<T> list, int fromIndex) { 1379 return list.subList(fromIndex, list.size()); 1380 } 1381 1382 /** 1383 * Returns an {@link ArrayList} filled with the given count of objects created 1384 * by the factory function. The current count is passed to the factory funciton. 1385 */ 1386 public static <T> ArrayList<T> repeat(Function<Integer, T> factory, int count) { 1387 CCSMAssert.isFalse(count < 0, 1388 () -> "Repeating objects for negative number " + count + " of objects is not possible."); 1389 ArrayList<T> result = new ArrayList<>(count); 1390 1391 for (int i = 0; i < count; i++) { 1392 result.add(factory.apply(count)); 1393 } 1394 1395 return result; 1396 } 1397}