-
Notifications
You must be signed in to change notification settings - Fork 1
/
IterPart.hx
127 lines (119 loc) · 4.09 KB
/
IterPart.hx
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
package finitudeiterable;
import IterArmy;
import IterRange;
using Lambda;
/**
* Inter-partitions sequential iterator: IterPart.
* Array<T> is divided into ``n`` partitions.
* On each iteration, the next value of one of those partition is returned,
* in a sequential way.
*
* This is a representation of a second-order IterPart:
*
* *--------->*---------->
* 0 subiter1 10 subiter2 20
*
* @example
* using IterPart;
* import IterRange.range as range;
* ...
* for (x in [ for (i in 0...21) i ].iterPart(2))
* trace(x);
* @endexample
*
* It will yield 0,10,1,11,2,12,13,3,14,4,15,5,16,6,17,7,18,8,19,9,20.
*
* Order n and negative orders
* ---------------------------
*
* ```
* IterPart Representation Inner-iterators
* ------------------------------------------------------
* order 1 *---------------------> 1
* order 2 *--------->*----------> 2
* order 3 *---->*-------->*-----> 3
* order 4 *--->*---->*---->*----> 4
* etc.
*
* A negative order reverts this:
*
* Order -1 <---------------------*
* Order -2 <----------*<---------*
* Order -3 <------*<------*<-----*
* etc.
*
* Order 0 is equivalent to IterVoid.
* ```
*
* @example
* // negative 3rd order IterPart:
* for (x in [0,1,2,3,4,5,6,7,8,9].iterPartition(-3))
* trace(x);
* @endexample
*
* Note
* ----
*
* If n >= array.length, 1 will be used instead. This is because it would
* have the same result, and also because it simplifies things internally.
*
* IterMeet<T> is also an Iterable<T>. This means `using Lambda` we can do non-linear searches:
* [ for (i in [0...1000]) i].iterMeet(5).find( is_a_good_number ) ];
*
* The search will be performed non-linearly, and will stop ASAP.
*
* More
* ----
*
* If you like this, check out the nice ```Loosy/FP.hx``` (functional
* programming library of methods) by Sledorze. It's a nice and powerful extension
* to Lambda and makes a nice companion to this library of Iterators.
*
* @sa See also `IterReverse` and `IterMeet` in this library for alternative
* ways of iterating arrays.
*/
class IterPart<T> {
var a : Array<T>;
var orign : Int; ///< So it's recalled w/ iterator()
var n : Int;
var itArmy : IterArmy<Int>; ///< Int bc the army iterates on indexes
/**
* @param (Array<T>) Array to iterate using a IterPart
* @param (Int n) Number of partitions.
* This will be set to 1 if n >= ar.length (it would return
* the same result).
* n<0 will have subiterator run backwards.
* n=0 will not iterate.
**/
public function new(ar:Array<T>, parts:Int) {
orign = parts;
a = ar;
var isReversed = parts < 0;
n = cast Math.abs(parts);
if (n >= ar.length) n = 1;
if (n == 0) {
// order 0 is no iterator.
itArmy = new IterArmy<Int>([]);
}
else {
var departures = new IterRange<Float>(0, a.length, a.length / n).array();
// ----------------------------------------------------
var i = 0;
var soldiers = new List<IterRange<Int>>();
var ab:Int = cast Math.floor(departures[0]);
while (++i < n) { // n-1 bc we want to set last soldier manually
var ad:Int = cast Math.floor(departures[i]);
soldiers.add(new IterRange<Int>(ab, ad, 1, isReversed));
ab = ad;
}
soldiers.add(new IterRange<Int>(ab, a.length, 1, isReversed));
itArmy = new IterArmy<Int>(soldiers);
// ---------------------------
}
}
public inline static function iterPart<T>(ar:Array<T>, parts:Int) : IterableIterator<T>
return new IterPart(ar, parts);
public inline function hasNext() return itArmy.hasNext();
public inline function next() return a[itArmy.next()];
public inline function iterator():IterableIterator<T> return new IterPart(a, orign);
}