1 /// Returns an `optional` index of an element.
2 module ddash.algorithm.index;
3
4 ///
5 unittest {
6 import optional: some, none;
7
8 auto arr1 = [1, 2, 3, 4];
9
10 assert(arr1.indexWhere!(a => a % 2 == 0) == some(1));
11 assert(arr1.lastIndexWhere!(a => a % 2 == 0) == some(3));
12
13 assert(arr1.indexWhere!(a => a == 5) == none);
14 assert(arr1.lastIndexWhere!(a => a % 2 == 0)(2) == some(1));
15
16 auto arr2 = [1, 2, 1, 2];
17
18 assert(arr2.indexOf(2) == some(1));
19 }
20
21
22 import ddash.common;
23
24 /**
25 Returns `optional` index of the first element predicate returns true for.
26
27 Params:
28 pred = unary function that returns true for some element
29 range = the input range to search
30 fromIndex = which index to start searching from
31
32 Returns:
33 `some!size_t` or `none` if no element was found
34
35 Since:
36 0.0.1
37 */
38 auto indexWhere(alias pred, Range)(Range range, size_t fromIndex = 0)
39 if (from!"std.range".isInputRange!Range
40 && from!"bolts.traits".isUnaryOver!(pred, from!"std.range".ElementType!Range))
41 {
42 import std.range: drop;
43 import std.functional: unaryFun;
44 import ddash.algorithm.internal: countUntil;
45 auto r = range.drop(fromIndex);
46 return r.countUntil!((a, b) => unaryFun!pred(a))(r) + fromIndex;
47 }
48
49 ///
50 unittest {
51 import optional: some, none;
52 assert([1, 2, 3, 4].indexWhere!(a => a % 2 == 0) == some(1));
53 assert([1, 2, 3, 4].indexWhere!(a => a == 5) == none);
54 assert([1, 2, 3, 4].indexWhere!(a => a % 2 == 0)(2) == some(3));
55 }
56
57 /**
58 Returns `optional` index of the last element predicate returns true for.
59
60 Params:
61 pred = unary function that returns true for some element
62 range = the input range to search
63 fromIndex = which index from the end to start searching from
64
65 Returns:
66 `some!size_t` or `none` if no element was found
67
68 Since:
69 0.0.1
70 */
71 auto lastIndexWhere(alias pred, Range)(Range range, size_t fromIndex = 0)
72 if (from!"std.range".isBidirectionalRange!Range
73 && from!"bolts.traits".isUnaryOver!(pred, from!"std.range".ElementType!Range))
74 {
75 import std.range: retro, walkLength;
76 import ddash.range: withFront;
77 return range
78 .retro
79 .indexWhere!pred(fromIndex)
80 .withFront!(a => range.walkLength - a - 1);
81 }
82
83 ///
84 unittest {
85 import optional: some, none;
86 assert([1, 2, 3, 4].lastIndexWhere!(a => a % 2 == 0) == some(3));
87 assert([1, 2, 3, 4].lastIndexWhere!(a => a == 5) == none);
88 assert([1, 2, 3, 4].lastIndexWhere!(a => a % 2 == 0)(2) == some(1));
89 }
90
91 /**
92 Finds the first element in a range that equals some value
93
94 Params:
95 range = an input range
96 value = value to search for
97 fromIndex = which index to start searching from
98
99 Returns:
100 An `Optional!T`
101
102 Since:
103 0.0.1
104 */
105 auto indexOf(Range, T)(Range range, T value, size_t fromIndex = 0) if (from!"std.range".isInputRange!Range) {
106 import std.range: drop;
107 import ddash.algorithm.internal: countUntil;
108 import ddash.range: withFront;
109 return range
110 .drop(fromIndex)
111 .countUntil(value)
112 .withFront!(a => a + fromIndex);
113 }
114
115 ///
116 unittest {
117 import optional;
118 assert([1, 2, 1, 2].indexOf(2) == some(1));
119 assert([1, 2, 1, 2].indexOf(2, 2) == some(3));
120 assert([1, 2, 1, 2].indexOf(3) == none);
121 }
122
123 /**
124 Finds the first element in a range that equals some value
125
126 Params:
127 range = an input range
128 value = value to search for
129 fromIndex = which index from the end to start searching from
130
131 Returns:
132 An `optional!T`
133
134 Since:
135 0.0.1
136 */
137 auto lastIndexOf(Range, T)(Range range, T value, size_t fromIndex = 0) if (from!"std.range".isBidirectionalRange!Range) {
138 import std.range: retro, walkLength;
139 import ddash.algorithm: indexOf;
140 import ddash.range: withFront;
141 return range
142 .retro
143 .indexOf(value, fromIndex)
144 .withFront!(a => range.walkLength - a - 1);
145 }
146
147 ///
148 unittest {
149 import optional;
150 assert([1, 2, 1, 2].indexOf(2) == some(1));
151 assert([1, 2, 1, 2].indexOf(2, 2) == some(3));
152 assert([1, 2, 1, 2].indexOf(3) == none);
153 }