1 /// Algorithms for doing calculations on a range. 2 module tern.algorithm.iteration; 3 4 import tern.traits; 5 import tern.object : loadLength; 6 import tern.functional; 7 8 public: 9 /** 10 * Calculates the distance between `comparer` and `comparee`. 11 * 12 * Params: 13 * comparee = The string to calculate from. 14 * comparee = The string to calculate against. 15 * 16 * Returns: 17 * The distance between `comparer` and `comparee`. 18 * 19 * Remarks: 20 * `A` and `B` must both be string types. 21 */ 22 size_t levenshteinDistance(A, B)(A comparer, B comparee) pure nothrow 23 if (isString!A && isString!B) 24 { 25 auto m = comparer.length + 1; 26 auto n = comparee.length + 1; 27 28 size_t[] dp; 29 30 dp.length = n; 31 32 foreach (j; 0..n) 33 dp[j] = j; 34 35 size_t diag; 36 size_t top; 37 size_t left; 38 39 foreach (i; 1..m) 40 { 41 diag = i - 1; 42 top = i; 43 44 foreach (j; 1..n) 45 { 46 left = dp[j]; 47 int cost = (comparer[i - 1] == comparee[j - 1]) ? 0 : 1; 48 dp[j] = top + 1; 49 50 if (dp[j - 1] + 1 < dp[j]) 51 dp[j] = dp[j - 1] + 1; 52 53 if (diag + cost < dp[j]) 54 dp[j] = diag + cost; 55 56 diag = left; 57 top = dp[j]; 58 } 59 } 60 61 return dp[n - 1]; 62 } 63 64 /** 65 * Calculates the difference between `comparer` and `comparee`. 66 * 67 * Params: 68 * comparee = The range to calculate from. 69 * comparee = The range to calculate against. 70 * 71 * Returns: 72 * The difference between `comparer` and `comparee`. 73 */ 74 size_t difference(A, B)(A comparer, B comparee) 75 if (isIndexable!A && isIndexable!B) 76 { 77 size_t ret = comparer.loadLength - comparee.length; 78 foreach (i; 0..comparee.loadLength) 79 { 80 if (i >= comparer.length) 81 return ret; 82 83 if (comparee[i] != comparer[i]) 84 ret++; 85 } 86 return ret; 87 } 88 89 /** 90 * Calculates the sum of all values in `range`. 91 * 92 * Params: 93 * range = The range to sum. 94 * 95 * Returns: 96 * The sum of all values in `range`. 97 */ 98 ElementType!T sum(T)(T range) 99 if (isForward!T && isIntegral!(ElementType!T)) 100 { 101 ElementType!T sum; 102 foreach (u; range) 103 sum += u; 104 return sum; 105 } 106 107 /** 108 * Calculates the mean of all values in `range`. 109 * 110 * Params: 111 * range = The range to mean. 112 * 113 * Returns: 114 * The mean of all values in `range`. 115 */ 116 ElementType!T mean(T)(T range) 117 if (isIndexable!T && isIntegral!(ElementType!T)) 118 { 119 return range.sum / range.loadLength; 120 } 121 122 /** 123 * Folds all values in `range` based on a predicate. 124 * 125 * Params: 126 * F = The function to use for folding. 127 * range = The range to fold. 128 * 129 * Returns: 130 * Return value of `F` after folding. 131 */ 132 auto fold(alias F, T)(T range) 133 if (isIndexable!T && isCallable!F) 134 { 135 return range.plane!(F, () => true); 136 } 137 138 /** 139 * Creates an array of all unique values in `range`. 140 * 141 * Params: 142 * range = The range to search for uniques in. 143 * 144 * Returns: 145 * An array of all unique values in `range`. 146 */ 147 ElementType!T[] uniq(T)(T range) 148 if (isIndexable!T) 149 { 150 bool[ElementType!T] ret; 151 foreach (u; range) 152 { 153 if (u !in ret) 154 ret[u] = true; 155 } 156 return ret.keys; 157 } 158 159 /** 160 * Gets the last value in `range` that abides by `F`, or the default value of `T`. 161 * 162 * Params: 163 * F = The function predicate. 164 * range = The range to be predicated. 165 * 166 * Returns: 167 * The last value in `range` that abides by `F`, or the default value of `T`. 168 */ 169 ElementType!T lastOrDefault(alias F, T)(T range) 170 if (isIndexable!T && isCallable!F) 171 { 172 auto ret = range.filter!F; 173 return ret.length == 0 ? T.init : ret[$-1]; 174 } 175 176 /** 177 * Gets the first value in `range` that abides by `F`, or the default value of `T`. 178 * 179 * Params: 180 * F = The function predicate. 181 * range = The range to be predicated. 182 * 183 * Returns: 184 * The first value in `range` that abides by `F`, or the default value of `T`. 185 */ 186 ElementType!T firstOrDefault(alias F, T)(T range) 187 if (isIndexable!T && isCallable!F) 188 { 189 auto ret = range.filter!F; 190 return ret.length == 0 ? T.init : ret[0]; 191 } 192 193 /** 194 * Concats `range` to itself `iter` times. 195 * 196 * Params: 197 * range = The range to repeat. 198 * iter = The number of iterations to repeat. 199 * 200 * Returns: 201 * The new repeated form of `range`. 202 */ 203 T repeat(T)(T range, size_t iter) 204 { 205 T ret = range; 206 foreach (i; 0..iter) 207 ret ~= range; 208 return ret; 209 } 210 211 /** 212 * Creates a `size_t[][]` holding every indices combination of a range of `length`. 213 * 214 * Params: 215 * length = Length of hypothetical range to derive combinations from. 216 * 217 * Returns: 218 * `size_t[][]` containing every indices combination of a range of `length`. 219 */ 220 size_t[][] combinations(size_t length) pure nothrow 221 { 222 size_t[][] ret; 223 foreach (i; 0..(1 << length)) 224 { 225 size_t[] combination; 226 foreach (j; 0..length) 227 { 228 if (i & (1 << j)) 229 combination ~= j; 230 } 231 ret ~= combination; 232 } 233 return ret; 234 }