-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathRichIterator.java
More file actions
590 lines (537 loc) · 17.2 KB
/
RichIterator.java
File metadata and controls
590 lines (537 loc) · 17.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
package iterator;
import java.util.*;
import java.util.function.*;
public interface RichIterator<A> extends Iterator<A> {
// easy
/**
* @return true if there are no more elements, false otherwise
*/
default boolean isEmpty() {
return !hasNext();
}
/**
* @return number of elements
*/
default int length() {
int count = 0;
RichIterator<A> tmpIter = new Wrapper<>( this.toList().iterator());
while (tmpIter.hasNext()) {
count++;
tmpIter.next();
}
return count;
}
/**
* @return the last element of the iterator
* @throws NoSuchElementException if the iterator is empty
*/
default A last() {
if (this.isEmpty()) {
throw new NoSuchElementException();
}
A next = null;
while (this.hasNext()) {
next = this.next();
}
return next;
}
/**
* @return the last element if not empty.
*/
default Optional<A> lastOptional() {
if (this.hasNext()) {
return Optional.of(this.last());
}
return Optional.empty();
}
/**
* @param elem the element
* @return the index of the element if exists, -1 otherwise
*/
default int indexOf(A elem) {
int idx = 0;
while (this.hasNext()) {
if (Objects.equals(elem, this.next())) {
return idx;
}
idx++;
}
return -1;
}
/**
* returns the first element fit to the given predicate
*
* @param f the predicate
* @return Optional.of(A) if exists, empty() otherwise.
*/
default Optional<A> find(Predicate<? super A> f) {
while (this.hasNext()) {
A currElement = this.next();
if (f.test(currElement)) {
return Optional.of(currElement);
}
}
return Optional.empty();
}
/**
* @return Optional.of(next) if exists or empty() otherwise
*/
default Optional<A> nextOptional() {
if (this.hasNext()) {
return Optional.of(this.next());
}
return Optional.empty();
}
/**
* executes the given Consumer on all the elements
*
* @param f the Consumer
*/
default void foreach(Consumer<? super A> f) {
while (this.hasNext()){
f.accept(this.next());
}
}
/**
* @param elem checks if the iterator has the element
* @return true if exists, false otherwise
*/
default boolean contains(A elem) {
while (this.hasNext()) {
if (elem.equals(this.next())) {
return true;
}
}
return false;
}
/**
* Converts the iterator to a collection using the collection factory
*
* @param collectionFactory a supplier that creates a new instance of the collection
* @param <C> the type of the collection to return
* e.g.
* RichIterator.apply(1,2,3,2,4,5).toCollection(HashSet::new) // HashSet(1,2,3,4,5)
* RichIterator.apply(1,2,3,2,4,5).toCollection(LinkedList::new) // LinkedList(1,2,3,2,4,5)
* @return the collection
*/
default <C extends Collection<A>> C toCollection(Supplier<C> collectionFactory) {
C newCol = collectionFactory.get();
newCol.addAll(toList());
return newCol;
}
/**
* @return a list built from the iterator's elements
*/
default List<A> toList() {
List<A> list = new ArrayList<>();
while (this.hasNext()) {
list.add(this.next());
}
return list;
}
/**
* @return a set built from the iterator's elements
*/
default Set<A> toSet() {
return this.toCollection(HashSet::new);
}
/**
* @param that other iterator
* @return true if this and that have the same elements in the same order
*/
default boolean sameElements(Iterator<A> that) {
while (that.hasNext() && this.hasNext()) {
if (!this.next().equals(that.next())) {
return false;
}
}
return !(that.hasNext() || this.hasNext());
}
// hard
/**
* builds an iterator with only the given element
*
* @param elem the element
* @param <A> the type
* @return an iterator that contains only this element
*/
static <A> RichIterator<A> pure(A elem) {
return apply(elem);
}
/**
* finds the maximum element based on the given comparator
*
* @param comparator the comparator
* @return the maximum element
* @throws NoSuchElementException if the iterator is empty
*/
default A max(Comparator<? super A> comparator) {
return this.toList().stream().max(comparator).orElse(null);
}
/**
* finds the minimum element based on the given comparator
*
* @param comparator the comparator
* @return the minimum element
* @throws NoSuchElementException if the iterator is empty
*/
default A min(Comparator<? super A> comparator) {
return this.toList().stream().min(comparator).orElse(null);
}
/**
* converts the iterator to new one after the mapping function
*
* @param f the function
* @param <B> the new type
* @return a new Iterator.
*/
default <B> RichIterator<B> map(Function<? super A, ? extends B> f) {
throw new NotImplementedException();
}
/**
* @param f the function to apply on each element.
* @return an iterator with the method applied on all the elements
* e.g.
* Iterator itr = Iterator(1,2,3).tapEach(System.out::print).foreach(System.out::print)
* output (printed): 112233
*/
default RichIterator<A> tapEach(Consumer<? super A> f) {
throw new NotImplementedException();
}
/**
* reducing the elements to one according to the given function
*
* @param acc accumulate function (first element is the total, second element is the iterated element)
* @return the reduced element.
* @throws NoSuchElementException when the iterator is empty
* e.g.
* RichIterator.apply(1,2,3).reduce((total, a) -> total + a) // 6
* RichIterator.empty().reduce((total, a) -> null) // throws NoSuchElementException
* RichIterator.apply(1).reduce((total, a) -> total + a) // 1
*/
default A reduce(BiFunction<? super A, ? super A, ? extends A> acc) {
throw new NotImplementedException();
}
/**
* same as reduce but return Optional of result if exists or empty() if not.
*
* @param acc // see reduce.
* @return // see reduce
*/
default Optional<A> reduceOptional(BiFunction<? super A, ? super A, ? extends A> acc) {
throw new NotImplementedException();
}
/**
* Creates a String from the iterator.
*
* @param prefix Start of the string
* @param delimiter delimiter between elements
* @param suffix end of the string
* @return a string containing all the elments in the iterator.
* @implNote use previous functions to solve.
* e.g.
* RichIterator(1,2,3,4,5).mkString("[", ";","]") // [1;2;3;4;5]
* RichIterator(1).mkString("[", ";","]") // [1]
* RichIterator().mkString("[", ";","]") // []
*/
default String mkString(String prefix, String delimiter, String suffix) {
throw new NotImplementedException();
}
/**
* Creates a String from the iterator that starts with "RichIterator("
* and the elements are separated by ',' and ends with ')'
* e.g.
* RichIterator.apply(1,2,3,4,5).mkString() // RichIterator(1,2,3,4,5)
* RichIterator.empty().mkString() // RichIterator()
*
* @return a String
*/
default String mkString() {
throw new NotImplementedException();
}
/**
* adding the element at the end of the iterator
*
* @param elem the element
* @return an iterator with the element appended
* e.g.
* RichIterator.apply(1,2,3,4).append(5) // 1,2,3,4,5
*/
default RichIterator<A> append(A elem) {
throw new NotImplementedException();
}
/**
* same as append but with iterator
*
* @param elems the element
* @return an iterator with the elements appended
* e.g.
* RichIterator.apply(1,2,3,4).appendAll(Arrays.asList(5,6,7,8)) // 1,2,3,4,5,6,7,8
*/
default RichIterator<A> appendAll(Iterator<A> elems) {
throw new NotImplementedException();
}
/**
* adding the element at the start of the iterator
*
* @param elem the element
* @return an iterator with the element prepended
* e.g.
* RichIterator.apply(1,2,3,4).prepend(0) // 0,1,2,3,4
*/
default RichIterator<A> prepend(A elem) {
throw new NotImplementedException();
}
/**
* same as prepend but with iterator
*
* @param elems the element
* @return an iterator with the elements prepended
* e.g.
* RichIterator.apply(4,5,6,7).prependAll(Arrays.asList(1,2,3)) // 1,2,3,4,5,6,7
*/
default RichIterator<A> prependAll(Iterator<A> elems) {
throw new NotImplementedException();
}
/**
* removes the first n elements of the iterator
*
* @param n the number to drop
* @return the iterator without the first n elements or empty iterator if (n >= length)
* e.g.
* RichIterator.apply(1,2,3,4,5,1,2,3,4,5).drop(2) // 3,4,5,1,2,3,4,5
* RichIterator.apply(1,2,3,4,5,1,2,3,4,5).drop(20) // empty()
*/
default RichIterator<A> drop(int n) {
throw new NotImplementedException();
}
/**
* takes only the first n elements
*
* @param n number of elements
* @return an Iterator that has the first n elements (or less)
* e.g.
* RichIterator.apply(1,2,3,4,5,1,2,3,4,5).take(2) // 1,2
* RichIterator.apply(1,2,3,4,5).take(20) // 1,2,3,4,5
*/
default RichIterator<A> take(int n) {
throw new NotImplementedException();
}
/**
* "sums" the elements on the iterator from left to right
*
* @param zero the first element usually neutral
* @param acc accumulate function
* @param <B> new type
* @return the accumulated result
* e.g.
* RichIterator.apply(1,2,3,4,5).foldLeft(0, (x,y) -> x + y) // 15
* RichIterator.apply("a","b","c","d").foldLeft("", (x,y) -> x + y) // "abcd"
* empty().foldLeft(0, (x,y) -> x + y) // 0
*/
default <B> B foldLeft(B zero, BiFunction<? super B, ? super A, ? extends B> acc) {
throw new NotImplementedException();
}
/**
* "sums" the elements on the iterator from left to right
* but the result is an iterator where each element
* presents the "sum" of all elements till it.
* <p>
* e.g.
* Iterator(1,2,3,4,5).scanLeft(0, Integer::sum) // Iterator(0,1,3,6,10,15)
*/
default <B> RichIterator<B> scanLeft(B zero, BiFunction<? super B, ? super A, ? extends B> acc) {
throw new NotImplementedException();
}
/**
* generates a serial of elements that every element leads to the next one.
* <p>
* for example
* Iterator itr = RichIterator.iterate(0, x -> x + 1)
* itr.next() // 0
* itr.next() // 1
* itr.next() // 2
* itr.next() // 3
*
* @param first the first element
* @param progress the progress function
* @param <A> the type
* @return an iterator
*/
static <A> RichIterator<A> iterate(A first, Function<? super A, ? extends A> progress) {
throw new NotImplementedException();
}
/**
* creates a pair based iterator over, the left element comes from this and the right comes from that
* <p>
* for example:
* RichIterator(1,2,3).zip(RichIterator.apply("a","b","c","d")) // RichIterator((1,"a"), (2,"b"), (3,"c"))
*
* @param that the other
* @param <B> the other type
* @return zipped iterator
*/
default <B> RichIterator<Pair<A, B>> zip(Iterator<B> that) {
throw new NotImplementedException();
}
/**
* zips the current iterator with indices
* <p>
* for example:
* RichIterator(1,2,3).zipWithIndex() // RichIterator((1,0), (2,1), (3,2))
*
* @return the zipped iterator
*/
default RichIterator<Pair<A, Integer>> zipWithIndex() {
throw new NotImplementedException();
}
/**
* Converts the given iterator to map
*
* @param asPair a function that converts the elements to pair
* @param <K> key type
* @param <V> value type
* @return a map
*/
default <K, V> Map<K, V> toMap(Function<? super A, ? extends Pair<K, V>> asPair) {
throw new NotImplementedException();
}
// very hard
/**
* takes elements while the predicate returns true
*
* @param predicate the predicate
* @return the first elements that fulfill the predicate
* e.g.
* RichIterator.apply(1,2,3,4,5,1,2,3,4,5).takeWhile(x -> x <= 3) // 1,2,3
*/
default RichIterator<A> takeWhile(Predicate<? super A> predicate) {
throw new NotImplementedException();
}
/**
* takes elements until the predicate returns true
*
* @param predicate the predicate
* @return the first elements that not fulfill the predicate
* e.g.
* RichIterator.apply(1,2,3,4,5,1,2,3,4,5).takeUntil(x -> x > 3) // 1,2,3
*/
default RichIterator<A> takeUntil(Predicate<? super A> predicate) {
throw new NotImplementedException();
}
/**
* drops elements while the predicate returns true
*
* @param predicate the predicate
* @return removes the first elements that fulfill the predicate
* e.g.
* RichIterator.apply(1,2,3,4,5,1,2,3,4,5).dropWhile(x -> x <= 3) // 4,5,1,2,3,4,5
*/
default RichIterator<A> dropWhile(Predicate<? super A> predicate) {
throw new NotImplementedException();
}
/**
* drops elements until the predicate returns true
*
* @param predicate the predicate
* @return removes the first elements that not fulfill the predicate
* e.g.
* RichIterator.apply(1,2,3,4,5,1,2,3,4,5).dropUntil(x -> x >= 3) // 4,5,1,2,3,4,5
*/
default RichIterator<A> dropUntil(Predicate<? super A> predicate) {
throw new NotImplementedException();
}
/**
* extends the iterator to supply a method that yields the first element without moving to the next element.
* <p>
* for example:
* BuffedIterator itr = RichIterator.apply(1,2,3,4).buffed()
* <p>
* itr.head() // 1
* itr.head() // 1
* itr.head() // 1
* itr.next() // 1
* itr.head() // 2
* itr.next() // 2
*
* @return the iterator
*/
default BufferedIterator<A> buffered() {
throw new NotImplementedException();
}
/**
* distinct the elements in the iterator using equals() method.
*
* @return an iterator with distinct values
* e.g. Iterator(1,2,3,3,2,1,4).distinct() // Iterator(1,2,3,4)
*/
default RichIterator<A> distinct() {
throw new NotImplementedException();
}
/**
* converts every element to Iterator and then flat them to single iterator
* <p>
* for example:
* RichIterator.apply(1,2,3).flatMap(i -> RichIterator.apply(i,i,i)) // RichIterator(1,1,1,2,2,2,3,3,3)
* RichIterator.apply(1,2,3).flatMap(i -> RichIterator.empty()) // RichIterator.empty()
*
* @param f the function
* @param <B> the type
* @return the iterator
*/
default <B> RichIterator<B> flatMap(Function<? super A, ? extends Iterator<B>> f) {
throw new NotImplementedException();
}
/**
* return an iterator with only the elements fit the iterator
* <p>
* for example
* RichIterator itr = RichIterator.from(1,2,3,4,5,6,7,8)
* itr.filter(x -> x % 2 == 0) // RichIterator(2,4,6,8)
* itr.filter(x -> x > 10) // RichIterator.empty()
*
* @param f the predicate
* @return an iterator
*/
default RichIterator<A> filter(Predicate<? super A> f) {
throw new NotImplementedException();
}
// end
@SuppressWarnings("rawtypes")
RichIterator EMPTY = EmptyIterator.instance;
/**
* creates RichIterator based on the given elements
*
* @param elements the elements
* @param <A> the type
* @return the iterator
*/
@SafeVarargs
static <A> RichIterator<A> apply(A... elements) {
return RichIterator.from(Arrays.stream(elements).iterator());
}
/**
* Creates RichIterator based on the given Iterable
*
* @param that the iterable
* @param <A> the type
* @return the iterator
*/
static <A> RichIterator<A> from(Iterable<A> that) {
return from(that.iterator());
}
/**
* Extends the given iterator
*
* @param that the iterator
* @param <A> the type
* @return the given iterator but better.
*/
static <A> RichIterator<A> from(Iterator<A> that) {
return new Wrapper<>(that);
}
@SuppressWarnings("unchecked")
static <A> RichIterator<A> empty() {
return EMPTY;
}
}