Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
Iterables |
|
| 0.0;0 | ||||
Iterables$1 |
|
| 0.0;0 | ||||
Iterables$2 |
|
| 0.0;0 | ||||
Iterables$SelectingIterator |
|
| 0.0;0 | ||||
Iterables$TransformingIterator |
|
| 0.0;0 |
1 | /* | |
2 | Copyright 2004-2008 Paul R. Holser, Jr. All rights reserved. | |
3 | Licensed under the Academic Free License version 3.0 | |
4 | */ | |
5 | ||
6 | package jaggregate; | |
7 | ||
8 | import java.util.Iterator; | |
9 | import java.util.NoSuchElementException; | |
10 | ||
11 | import static jaggregate.internal.ArgumentChecks.*; | |
12 | import static jaggregate.internal.UnaryConditions.*; | |
13 | ||
14 | /** | |
15 | * Functions that offer {@linkplain Collection}-like functionality for | |
16 | * {@linkplain Iterable}s. | |
17 | * | |
18 | * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a> | |
19 | * @version $Id: Iterables.java,v 1.8 2008/10/03 19:01:23 pholser Exp $ | |
20 | */ | |
21 | public class Iterables { | |
22 | /** | |
23 | * Discourages instantiation. | |
24 | * | |
25 | * @throws UnsupportedOperationException always | |
26 | */ | |
27 | 1 | protected Iterables() { |
28 | 1 | throw new UnsupportedOperationException(); |
29 | } | |
30 | ||
31 | /** | |
32 | * Answers {@code true} if the given discriminator answers {@code true} for every | |
33 | * element yielded by the given iterable, or if the iterable yields no elements; | |
34 | * otherwise answers {@code false}. | |
35 | * <p/> | |
36 | * It is unspecified whether {@code discriminator} will be evaluated with every | |
37 | * element that the iterable yields. | |
38 | * | |
39 | * @param <E> type of the items to iterate over | |
40 | * @param items the items to iterate over | |
41 | * @param discriminator the discriminator to evaluate | |
42 | * @return whether {@code discriminator} is {@code true} for every element | |
43 | * @throws NullPointerException if {@code items} or {@code discriminator} | |
44 | * is {@code null} | |
45 | * @see Collection#allSatisfy(UnaryCondition) | |
46 | */ | |
47 | public static <E> boolean allSatisfy( Iterable<? extends E> items, | |
48 | UnaryCondition<? super E> discriminator ) { | |
49 | ||
50 | 5 | ensureNotNull( discriminator, DISCRIMINATOR ); |
51 | ||
52 | 4 | for ( E each : items ) { |
53 | 6 | if ( !discriminator.matches( each ) ) |
54 | 1 | return false; |
55 | } | |
56 | ||
57 | 2 | return true; |
58 | } | |
59 | ||
60 | /** | |
61 | * Answers {@code true} if the given discriminator answers {@code true} for any | |
62 | * element yielded by the given iterable; answers {@code false} otherwise, or if the | |
63 | * iterable yields no elements. | |
64 | * <p/> | |
65 | * It is unspecified whether {@code discriminator} will be evaluated with every | |
66 | * element that the iterable yields. | |
67 | * | |
68 | * @param <E> type of the items to iterate over | |
69 | * @param items the items to iterate over | |
70 | * @param discriminator the discriminator to evaluate | |
71 | * @return whether {@code discriminator} is {@code true} for any element | |
72 | * @throws NullPointerException if {@code items} or {@code discriminator} | |
73 | * is {@code null} | |
74 | * @see Collection#anySatisfy(UnaryCondition) | |
75 | */ | |
76 | public static <E> boolean anySatisfy( Iterable<? extends E> items, | |
77 | UnaryCondition<? super E> discriminator ) { | |
78 | ||
79 | 5 | ensureNotNull( discriminator, DISCRIMINATOR ); |
80 | ||
81 | 4 | for ( E each : items ) { |
82 | 6 | if ( discriminator.matches( each ) ) |
83 | 1 | return true; |
84 | } | |
85 | ||
86 | 2 | return false; |
87 | } | |
88 | ||
89 | /** | |
90 | * Wraps the given iterable with another iterable whose iterator will transform | |
91 | * items using the given functor. | |
92 | * | |
93 | * @param <E> type of the items to iterate over | |
94 | * @param <R> type of the transformed iterated items | |
95 | * @param items the iterable to wrap | |
96 | * @param transformer functor used to transform elements | |
97 | * @return the wrapping, transforming iterable | |
98 | * @throws NullPointerException if {@code items} or {@code transformer} is | |
99 | * {@code null} | |
100 | * @see Collection#collect(UnaryFunctor) | |
101 | */ | |
102 | public static <E, R> Iterable<R> collect( final Iterable<? extends E> items, | |
103 | final UnaryFunctor<? super E, ? extends R> transformer ) { | |
104 | ||
105 | 10 | ensureNotNull( items, ITERABLE ); |
106 | 9 | ensureNotNull( transformer, TRANSFORMER ); |
107 | ||
108 | 8 | return new Iterable<R>() { |
109 | 8 | public Iterator<R> iterator() { |
110 | 8 | return new TransformingIterator<E, R>( items.iterator(), transformer ); |
111 | } | |
112 | }; | |
113 | } | |
114 | ||
115 | /** | |
116 | * Answers the first element yielded by the given iterable for which the given | |
117 | * discriminator answers {@code true} when given that element as an argument. | |
118 | * <p/> | |
119 | * {@code discriminator} will only be evaluated until such an object is found or | |
120 | * until the iterable yields no elements to use as arguments. That is, there may | |
121 | * be elements that the iterable yields that are never used as arguments to | |
122 | * {@code discriminator}. | |
123 | * | |
124 | * @param <E> type of the items to iterate over | |
125 | * @param items the items to iterate over | |
126 | * @param discriminator the discriminator to evaluate | |
127 | * @return the first item that satisfies {@code discriminator} | |
128 | * @throws java.util.NoSuchElementException if no item satisfies | |
129 | * {@code discriminator} | |
130 | * @throws NullPointerException if {@code items} or {@code discriminator} is | |
131 | * {@code null} | |
132 | */ | |
133 | public static <E> E detect( Iterable<? extends E> items, | |
134 | UnaryCondition<? super E> discriminator ) { | |
135 | ||
136 | 5 | ensureNotNull( discriminator, DISCRIMINATOR ); |
137 | ||
138 | 4 | for ( E each : items ) { |
139 | 5 | if ( discriminator.matches( each ) ) |
140 | 1 | return each; |
141 | } | |
142 | ||
143 | 2 | throw new NoSuchElementException(); |
144 | } | |
145 | ||
146 | /** | |
147 | * Answers the number of elements yielded by the given iterable which are equivalent | |
148 | * to the given target. | |
149 | * | |
150 | * @param <E> type of the items to iterate over | |
151 | * @param items the items to iterate over | |
152 | * @param target the object to compare against | |
153 | * @return the number of occurrences of equivalent objects yielded by the iterable | |
154 | * @throws NullPointerException if {@code items} is {@code null} | |
155 | */ | |
156 | public static <E> int occurrencesOf( Iterable<? extends E> items, E target ) { | |
157 | 5 | int occurrences = 0; |
158 | ||
159 | 5 | for ( E each : items ) { |
160 | 24 | if ( Objects.areEqual( each, target ) ) |
161 | 6 | ++occurrences; |
162 | } | |
163 | ||
164 | 4 | return occurrences; |
165 | } | |
166 | ||
167 | /** | |
168 | * Answers the final result of evaluating the given operation using each element of | |
169 | * the given iterable and the previous evaluation result as the parameters. | |
170 | * <p/> | |
171 | * The first evaluation of {@code operation} is performed with the given initial | |
172 | * value as the first parameter, and the first element of the iterable as the second | |
173 | * parameter. Subsequent evaluations are done with the result of the previous | |
174 | * evaluation as the first parameter, and the next element as the second parameter. | |
175 | * The result of the last evaluation is answered. | |
176 | * | |
177 | * @param <E> type of the items to iterate over | |
178 | * @param <R> type of the initial value, intermediate results, and final result | |
179 | * @param items the items to iterate over | |
180 | * @param initialValue first parameter for the first evaluation | |
181 | * @param operation the operation to evaluate | |
182 | * @return the result of the last evaluation | |
183 | * @throws NullPointerException if {@code items} or {@code operation} is {@code null} | |
184 | * @see Collection#inject(Object, BinaryFunctor) | |
185 | */ | |
186 | public static <E, R> R inject( Iterable<? extends E> items, R initialValue, | |
187 | BinaryFunctor<? super R, ? super E, ? extends R> operation ) { | |
188 | ||
189 | 4 | ensureNotNull( operation, OPERATION ); |
190 | ||
191 | 3 | R result = initialValue; |
192 | 3 | for ( E each : items ) |
193 | 4 | result = operation.evaluate( result, each ); |
194 | ||
195 | 2 | return result; |
196 | } | |
197 | ||
198 | /** | |
199 | * Removes items from the given iterable which match the given predicate. | |
200 | * | |
201 | * @param <E> type of the items to iterate over | |
202 | * @param items items to iterate over | |
203 | * @param discriminator tells which items should be removed | |
204 | * @return {@code true} if any removals occurred | |
205 | * @throws NullPointerException if {@code items} or {@code discriminator} | |
206 | * is {@code null} | |
207 | * @throws UnsupportedOperationException if {@code items}'s iterator does not | |
208 | * support removal | |
209 | * @see ExtensibleCollection#removeIf(UnaryCondition) | |
210 | */ | |
211 | public static <E> boolean removeIf( Iterable<? extends E> items, | |
212 | UnaryCondition<? super E> discriminator ) { | |
213 | ||
214 | 11 | ensureNotNull( discriminator, DISCRIMINATOR ); |
215 | ||
216 | 10 | boolean removalsOccurred = false; |
217 | ||
218 | 10 | for ( Iterator<? extends E> it = items.iterator(); it.hasNext(); ) { |
219 | 16 | if ( discriminator.matches( it.next() ) ) { |
220 | 9 | it.remove(); |
221 | 7 | removalsOccurred = true; |
222 | } | |
223 | } | |
224 | ||
225 | 6 | return removalsOccurred; |
226 | } | |
227 | ||
228 | /** | |
229 | * Removes items from the given iterable which do not match the given predicate. | |
230 | * | |
231 | * @param <E> type of the items to iterate over | |
232 | * @param items items to iterate over | |
233 | * @param discriminator tells which items should be retained | |
234 | * @return {@code true} if any removals occurred | |
235 | * @throws NullPointerException if {@code items} or {@code discriminator} | |
236 | * is {@code null} | |
237 | * @throws UnsupportedOperationException if {@code items}'s iterator does not | |
238 | * support removal | |
239 | * @see ExtensibleCollection#retainIf(UnaryCondition) | |
240 | */ | |
241 | public static <E> boolean retainIf( Iterable<? extends E> items, | |
242 | UnaryCondition<? super E> discriminator ) { | |
243 | ||
244 | 6 | return removeIf( items, not( discriminator ) ); |
245 | } | |
246 | ||
247 | /** | |
248 | * Wraps the given iterable with another iterable whose iterator will filter | |
249 | * out items which do not match the given predicate. | |
250 | * | |
251 | * @param <E> type of the items to iterate over | |
252 | * @param items the iterable to wrap | |
253 | * @param discriminator predicate used to filter elements | |
254 | * @return the wrapping, filtering iterable | |
255 | * @throws NullPointerException if {@code items} or {@code discriminator} is | |
256 | * {@code null} | |
257 | * @see Collection#select(UnaryCondition) | |
258 | */ | |
259 | public static <E> Iterable<E> select( final Iterable<? extends E> items, | |
260 | final UnaryCondition<? super E> discriminator ) { | |
261 | ||
262 | 18 | ensureNotNull( items, ITERABLE ); |
263 | 17 | ensureNotNull( discriminator, DISCRIMINATOR ); |
264 | ||
265 | 16 | return new Iterable<E>() { |
266 | 16 | public Iterator<E> iterator() { |
267 | 16 | return new SelectingIterator<E>( items.iterator(), discriminator ); |
268 | } | |
269 | }; | |
270 | } | |
271 | ||
272 | private static class SelectingIterator<E> implements Iterator<E> { | |
273 | private final Iterator<? extends E> wrapped; | |
274 | private final UnaryCondition<? super E> discriminator; | |
275 | private boolean askedHasNext; | |
276 | 16 | private boolean hasNext = true; |
277 | 16 | private E current = null; |
278 | ||
279 | SelectingIterator( Iterator<? extends E> wrapped, | |
280 | 16 | UnaryCondition<? super E> discriminator ) { |
281 | ||
282 | 16 | this.wrapped = wrapped; |
283 | 16 | this.discriminator = discriminator; |
284 | 16 | } |
285 | ||
286 | /** | |
287 | * {@inheritDoc} | |
288 | */ | |
289 | public boolean hasNext() { | |
290 | 20 | askedHasNext = true; |
291 | ||
292 | 20 | advance(); |
293 | ||
294 | 20 | return hasNext; |
295 | } | |
296 | ||
297 | /** | |
298 | * {@inheritDoc} | |
299 | */ | |
300 | public E next() { | |
301 | 22 | if ( !askedHasNext ) |
302 | 10 | advance(); |
303 | ||
304 | 22 | if ( !hasNext ) |
305 | 4 | throw new NoSuchElementException(); |
306 | ||
307 | 18 | return current; |
308 | } | |
309 | ||
310 | /** | |
311 | * {@inheritDoc} | |
312 | */ | |
313 | public void remove() { | |
314 | 4 | throw new UnsupportedOperationException(); |
315 | } | |
316 | ||
317 | private void advance() { | |
318 | 48 | while ( wrapped.hasNext() ) { |
319 | 36 | current = wrapped.next(); |
320 | ||
321 | 36 | if ( discriminator.matches( current ) ) |
322 | 18 | return; |
323 | } | |
324 | ||
325 | 12 | hasNext = false; |
326 | 12 | } |
327 | } | |
328 | ||
329 | private static class TransformingIterator<E, R> implements Iterator<R> { | |
330 | private Iterator<? extends E> wrapped; | |
331 | private UnaryFunctor<? super E, ? extends R> transformer; | |
332 | ||
333 | TransformingIterator( Iterator<? extends E> wrapped, | |
334 | 8 | UnaryFunctor<? super E, ? extends R> transformer ) { |
335 | ||
336 | 8 | this.wrapped = wrapped; |
337 | 8 | this.transformer = transformer; |
338 | 8 | } |
339 | ||
340 | /** | |
341 | * {@inheritDoc} | |
342 | */ | |
343 | public boolean hasNext() { | |
344 | 11 | return wrapped.hasNext(); |
345 | } | |
346 | ||
347 | /** | |
348 | * {@inheritDoc} | |
349 | */ | |
350 | public R next() { | |
351 | 13 | return transformer.evaluate( wrapped.next() ); |
352 | } | |
353 | ||
354 | /** | |
355 | * {@inheritDoc} | |
356 | */ | |
357 | public void remove() { | |
358 | 2 | throw new UnsupportedOperationException(); |
359 | } | |
360 | } | |
361 | } |