View Javadoc
1   /*
2    * *************************************************************************************************************************************************************
3    *
4    * TheseFoolishThings: Miscellaneous utilities
5    * http://tidalwave.it/projects/thesefoolishthings
6    *
7    * Copyright (C) 2009 - 2025 by Tidalwave s.a.s. (http://tidalwave.it)
8    *
9    * *************************************************************************************************************************************************************
10   *
11   * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
12   * You may obtain a copy of the License at
13   *
14   *     http://www.apache.org/licenses/LICENSE-2.0
15   *
16   * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
17   * CONDITIONS OF ANY KIND, either express or implied.  See the License for the specific language governing permissions and limitations under the License.
18   *
19   * *************************************************************************************************************************************************************
20   *
21   * git clone https://bitbucket.org/tidalwave/thesefoolishthings-src
22   * git clone https://github.com/tidalwave-it/thesefoolishthings-src
23   *
24   * *************************************************************************************************************************************************************
25   */
26  package it.tidalwave.util;
27  
28  import jakarta.annotation.Nonnull;
29  import java.util.ArrayList;
30  import java.util.Collection;
31  import java.util.Collections;
32  import java.util.Comparator;
33  import java.util.List;
34  import java.util.Optional;
35  import lombok.AccessLevel;
36  import lombok.NoArgsConstructor;
37  import static java.util.Collections.emptyList;
38  
39  /***************************************************************************************************************************************************************
40   *
41   * This class contains a bunch of utility methods for manipulating lists.
42   *
43   * @author  Fabrizio Giudici
44   * @since   3.2-ALPHA-13
45   * @it.tidalwave.javadoc.stable
46   *
47   **************************************************************************************************************************************************************/
48  @NoArgsConstructor(access = AccessLevel.PRIVATE)
49  public final class CollectionUtils
50    {
51      /***********************************************************************************************************************************************************
52       * Appends a list to an object. The resulting list is mutable.
53       *
54       * @param     <T>       the type of list items
55       * @param     list      the list
56       * @param     object    the list to append
57       * @return              the list with the appended object
58       *
59       * @it.tidalwave.javadoc.stable
60       **********************************************************************************************************************************************************/
61      @Nonnull
62      public static <T> List<T> concat (@Nonnull final List<? extends T> list, @Nonnull final T object)
63        {
64          final List<T> result = new ArrayList<>(list);
65          result.add(object);
66          return result;
67        }
68  
69      /***********************************************************************************************************************************************************
70       * Returns a concatenation of the given {@link Collection}s.
71       *
72       * @param     <T>         the static type
73       * @param     collections the input collections
74       * @return                the concatenation
75       *
76       * @it.tidalwave.javadoc.stable
77       **********************************************************************************************************************************************************/
78      @Nonnull @SafeVarargs
79      public static <T> List<T> concatAll (@Nonnull final Collection<? extends T>... collections)
80        {
81          final List<T> result = new ArrayList<>();
82  
83          for (final var collection : collections)
84            {
85              result.addAll(collection);
86            }
87  
88          return result;
89        }
90  
91      /***********************************************************************************************************************************************************
92       * Reverses a list. The resulting list is mutable.
93       *
94       * @param     <T>       the type of list items
95       * @param     list      the list
96       * @return              the reversed list
97       *
98       * @it.tidalwave.javadoc.stable
99       **********************************************************************************************************************************************************/
100     @Nonnull
101     public static <T> List<T> reversed (@Nonnull final List<? extends T> list)
102       {
103         final List<T> result = new ArrayList<>(list);
104         Collections.reverse(result);
105         return result;
106       }
107 
108     /***********************************************************************************************************************************************************
109      * Sorts a list. The resulting list is mutable.
110      *
111      * @param     <T>       the type of list items
112      * @param     list      the list
113      * @return              the sorted list
114      * @since     3.2-ALPHA-13
115      *
116      * @it.tidalwave.javadoc.stable
117      **********************************************************************************************************************************************************/
118     @Nonnull
119     public static <T extends Comparable<? super T>> List<T> sorted (@Nonnull final List<? extends T> list)
120       {
121         final var result = new ArrayList<T>(list);
122         Collections.sort(result);
123         return result;
124       }
125 
126     /***********************************************************************************************************************************************************
127      * Sorts a list with a given {@link Comparator}. The resulting list is mutable.
128      *
129      * @param     <T>         the type of list items
130      * @param     list        the list
131      * @param     comparator  the comparator
132      * @return                the sorted list
133      * @since     3.2-ALPHA-13
134      *
135      * @it.tidalwave.javadoc.stable
136      **********************************************************************************************************************************************************/
137     @Nonnull
138     public static <T> List<T> sorted (@Nonnull final List<? extends T> list,
139                                       @Nonnull final Comparator<? super T> comparator)
140       {
141         final var result = new ArrayList<T>(list);
142         result.sort(comparator);
143         return result;
144       }
145 
146     /***********************************************************************************************************************************************************
147      * Returns the (optional) first element of a list.
148      *
149      * @param     <T>       the type of list items
150      * @param     list      the list
151      * @return              the first element
152      *
153      * @it.tidalwave.javadoc.stable
154      **********************************************************************************************************************************************************/
155     @Nonnull
156     public static <T> Optional<T> optionalHead (@Nonnull final List<? extends T> list)
157       {
158         return list.isEmpty() ? Optional.empty() : Optional.of(list.get(0));
159       }
160 
161     /***********************************************************************************************************************************************************
162      * Returns the first element of a list.
163      *
164      * @param     <T>       the type of list items
165      * @param     list      the list (cannot be empty)
166      * @return              the first element
167      * @throws    IllegalArgumentException  if the list is empty
168      *
169      * @it.tidalwave.javadoc.stable
170      **********************************************************************************************************************************************************/
171     @Nonnull
172     public static <T> T head (@Nonnull final List<? extends T> list)
173       {
174         if (list.isEmpty())
175           {
176             throw new IllegalArgumentException("List is empty");
177           }
178 
179         return list.get(0);
180       }
181 
182     /***********************************************************************************************************************************************************
183      * Returns the tail element of a list, that is a list without the first element. The tail of an empty list is an
184      * empty list. The resulting list is mutable.
185      *
186      * @param     <T>       the type of list items
187      * @param     list      the list
188      * @return              the tail of the list
189      *
190      * @it.tidalwave.javadoc.stable
191      **********************************************************************************************************************************************************/
192     @Nonnull
193     public static <T> List<T> tail (@Nonnull final List<? extends T> list)
194       {
195         return new ArrayList<>(list.subList(1, list.size()));
196       }
197 
198     /***********************************************************************************************************************************************************
199      * Return a sublist of the original {@link List}, from the given {@code from} and {@code to} index (not included).
200      * If the {@code from} index is negative and/or the {@code to} index is lower than the {@code from} index or if an
201      * attempt is made to read before the start or past the end of the list, truncation silently occurs.
202      *
203      * @param     <T>             the static type
204      * @param     list            the original list
205      * @param     from            the first index (included)
206      * @param     to              the last index (excluded)
207      * @return                    the sublist
208      * @since     3.2-ALPHA-17
209      **********************************************************************************************************************************************************/
210     @Nonnull
211     public static <T> List<T> safeSubList (@Nonnull final List<? extends T> list, final int from, final int to)
212       {
213         final var safeFrom = Math.max(from, 0);
214         final var safeTo = Math.min(list.size(), to);
215         return (safeFrom >= safeTo) ? emptyList() : new ArrayList<>(list.subList(safeFrom, safeTo));
216       }
217 
218     /***********************************************************************************************************************************************************
219      * Splits a given {@link List} at a set of boundaries. Each boundary is the starting point of a sublist to be
220      * returned.
221      *
222      * @param     <T>             the static type
223      * @param     list            the original list
224      * @param     boundaries      the boundaries
225      * @return                    a list of sublists
226      * @since     3.2-ALPHA-17
227      **********************************************************************************************************************************************************/
228     @Nonnull
229     public static <T> List<List<T>> split (@Nonnull final List<? extends T> list, final int ... boundaries)
230       {
231         final var result = new ArrayList<List<T>>();
232 
233         for (var i = 0; i < boundaries.length - 1; i++)
234           {
235             result.add(safeSubList(list, boundaries[i], boundaries[i + 1]));
236           }
237 
238         return result;
239       }
240   }