| 1 |
// SemiTwist Library |
|---|
| 2 |
// Written in the D programming language. |
|---|
| 3 |
|
|---|
| 4 |
module semitwist.util.array; |
|---|
| 5 |
|
|---|
| 6 |
import std.algorithm; |
|---|
| 7 |
import std.array; |
|---|
| 8 |
import std.functional; |
|---|
| 9 |
|
|---|
| 10 |
import semitwist.util.all; |
|---|
| 11 |
|
|---|
| 12 |
size_t maxLength(T)(T[][] arrays) |
|---|
| 13 |
{ |
|---|
| 14 |
size_t maxLen=0; |
|---|
| 15 |
foreach(T[] array; arrays) |
|---|
| 16 |
maxLen = max(maxLen, array.length); |
|---|
| 17 |
return maxLen; |
|---|
| 18 |
} |
|---|
| 19 |
|
|---|
| 20 |
size_t indexOfMin(T)(T[] array) |
|---|
| 21 |
{ |
|---|
| 22 |
T best = T.max; |
|---|
| 23 |
size_t bestIndex; |
|---|
| 24 |
foreach(size_t i, T elem; array) |
|---|
| 25 |
{ |
|---|
| 26 |
if(elem < best) |
|---|
| 27 |
{ |
|---|
| 28 |
best = elem; |
|---|
| 29 |
bestIndex = i; |
|---|
| 30 |
} |
|---|
| 31 |
} |
|---|
| 32 |
return bestIndex; |
|---|
| 33 |
} |
|---|
| 34 |
|
|---|
| 35 |
size_t indexOfMax(T)(T[] array) |
|---|
| 36 |
{ |
|---|
| 37 |
T best = T.min; |
|---|
| 38 |
size_t bestIndex; |
|---|
| 39 |
foreach(size_t i, T elem; array) |
|---|
| 40 |
{ |
|---|
| 41 |
if(elem > best) |
|---|
| 42 |
{ |
|---|
| 43 |
best = elem; |
|---|
| 44 |
bestIndex = i; |
|---|
| 45 |
} |
|---|
| 46 |
} |
|---|
| 47 |
return bestIndex; |
|---|
| 48 |
} |
|---|
| 49 |
|
|---|
| 50 |
//TODO: eliminate name collision with tango.text.Util |
|---|
| 51 |
//TODO: Is this the same as tango.core.Array.findIf()? |
|---|
| 52 |
/+size_t find(T)(T[] collection, bool delegate(T[], size_t) isFound, size_t start=0) |
|---|
| 53 |
{ |
|---|
| 54 |
for(size_t i=start; i<collection.length; i++) |
|---|
| 55 |
{ |
|---|
| 56 |
if(isFound(collection, i)) |
|---|
| 57 |
return i; |
|---|
| 58 |
} |
|---|
| 59 |
|
|---|
| 60 |
return collection.length; |
|---|
| 61 |
} |
|---|
| 62 |
+/ |
|---|
| 63 |
size_t findPrior(T)(T[] collection, bool delegate(T[], size_t) isFound, size_t start=(size_t).max) |
|---|
| 64 |
{ |
|---|
| 65 |
if(start == (size_t).max) |
|---|
| 66 |
start = collection.length-1; |
|---|
| 67 |
|
|---|
| 68 |
for(size_t i=start; i >= 0; i--) |
|---|
| 69 |
{ |
|---|
| 70 |
if(isFound(collection, i)) |
|---|
| 71 |
return i; |
|---|
| 72 |
} |
|---|
| 73 |
|
|---|
| 74 |
return collection.length; |
|---|
| 75 |
} |
|---|
| 76 |
|
|---|
| 77 |
/// Returns everything in 'from' minus the values in 'except'. |
|---|
| 78 |
// Note: using ref didn't work when params were (const string[] here).dup |
|---|
| 79 |
T allExcept(T)(T from, T except) |
|---|
| 80 |
{ |
|---|
| 81 |
T f = from.dup; |
|---|
| 82 |
T e = except.dup; |
|---|
| 83 |
f.sort(); |
|---|
| 84 |
e.sort(); |
|---|
| 85 |
return f.missingFrom(e); |
|---|
| 86 |
} |
|---|
| 87 |
T[] allExcept(T)(T[] from, T except) |
|---|
| 88 |
{ |
|---|
| 89 |
return allExcept(from, [except]); |
|---|
| 90 |
} |
|---|
| 91 |
|
|---|
| 92 |
/// Ex: toRangedPairs([3,4,5,5,6,6,10,25,26]) == [[3,6], [10,10], [25,26]] |
|---|
| 93 |
/// Only intended for integer types and other ordered types for which "x+1" makes sense. |
|---|
| 94 |
/// Input does not have to be sorted. |
|---|
| 95 |
/// The resulting pairs are sorted and are inclusive on both ends. |
|---|
| 96 |
/// Optionally takes a splitCond predicate so you can customize when the range ends. |
|---|
| 97 |
T[2][] toRangedPairs(alias splitCond = "b > a + 1", T)(T[] arr) |
|---|
| 98 |
{ |
|---|
| 99 |
alias binaryFun!(splitCond) splitCondDg; |
|---|
| 100 |
static if(!is(typeof(splitCondDg(T.init, T.init)) == bool)) |
|---|
| 101 |
static assert(false, "Invalid predicate passed to toRangedPairs: "~splitCond); |
|---|
| 102 |
|
|---|
| 103 |
if(arr.length == 0) |
|---|
| 104 |
return []; |
|---|
| 105 |
|
|---|
| 106 |
if(arr.length == 1) |
|---|
| 107 |
return [ [ arr[0], arr[0] ] ]; |
|---|
| 108 |
|
|---|
| 109 |
arr = array(sort(arr)); |
|---|
| 110 |
|
|---|
| 111 |
T[2][] ret; |
|---|
| 112 |
auto prevVal = arr[0]; |
|---|
| 113 |
auto startVal = arr[0]; |
|---|
| 114 |
foreach(val; arr[1..$]) |
|---|
| 115 |
{ |
|---|
| 116 |
if(splitCondDg(prevVal, val)) |
|---|
| 117 |
{ |
|---|
| 118 |
ret ~= [ startVal, prevVal ]; |
|---|
| 119 |
startVal = val; |
|---|
| 120 |
} |
|---|
| 121 |
prevVal = val; |
|---|
| 122 |
} |
|---|
| 123 |
ret ~= [ startVal, arr[$-1] ]; |
|---|
| 124 |
|
|---|
| 125 |
return ret; |
|---|
| 126 |
} |
|---|
| 127 |
|
|---|
| 128 |
mixin(unittestSemiTwistDLib(q{ |
|---|
| 129 |
|
|---|
| 130 |
// toRangedPairs |
|---|
| 131 |
mixin(deferEnsure!(q{ [12,3,7,4,10,5,9,12].toRangedPairs() }, q{ _ == [[3,5], [7,7], [9,10], [12,12]] })); |
|---|
| 132 |
mixin(deferEnsure!(q{ [1,20].toRangedPairs() }, q{ _ == [[1,1], [20,20]] })); |
|---|
| 133 |
|
|---|
| 134 |
})); |
|---|