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 }