1 /** 2 sorts stuff 3 */ 4 module ddash.algorithm.sort; 5 6 import ddash.common; 7 8 /** 9 Might or might not sort a range, depending on some static properties of a range. 10 11 $(LI If already sorted and no predicate then no op) 12 $(LI If not already sorted and no predicate then `sort(range)` is called) 13 $(LI If not already sorted and a predicate is provided then `sort!pred(range)` is called) 14 $(LI Else it's a no op and you get back the same range you passed in) 15 16 Since: 17 0.0.1 18 */ 19 auto ref maybeSort(alias less = null, Range)(auto ref Range range) { 20 import std.algorithm: sort; 21 import bolts.traits: isNullType; 22 import bolts.range: isSortedRange; 23 import std.functional: binaryFun; 24 static if (isNullType!less) { 25 static if (isSortedRange!Range) { 26 return range; 27 } else static if (is(typeof(sort(range)))) { 28 return sort(range); 29 } else { 30 return range; 31 } 32 } else static if (is(typeof(sort!(binaryFun!less)(range)))) { 33 return sort!(binaryFun!less)(range); 34 } else { 35 return range; 36 } 37 } 38 39 /// 40 unittest { 41 import bolts.range: isSortedRange; 42 43 struct A { // unsortable 44 int i; 45 } 46 47 struct B { // sortable 48 int i; 49 bool opCmp(B a) { 50 return i < a.i; 51 } 52 } 53 54 static assert( isSortedRange!([1].maybeSort)); 55 static assert(!isSortedRange!([A()].maybeSort)); 56 static assert( isSortedRange!([B()].maybeSort)); 57 static assert( isSortedRange!([A()].maybeSort!"a.i < b.i")); 58 } 59 60 61 /** 62 Maybe sorts a range using `maybeSort` by a publicly visible member variable or property of `ElemntType!Range` 63 64 Since: 65 0.0.1 66 */ 67 auto ref maybeSortBy(string member, alias less = null, Range)(auto ref Range range) { 68 import std.algorithm: sort; 69 import bolts.traits: isNullType; 70 import bolts.range: isSortedRange; 71 import std.functional: binaryFun; 72 static if (isNullType!less) { 73 static if (is(typeof(sortBy!member(range)))) { 74 return sortBy!member(range); 75 } else { 76 return range; 77 } 78 } else static if (is(typeof(sortBy!(member, binaryFun!less)(range)))) { 79 return sortBy!(member, binaryFun!less)(range); 80 } else { 81 return range; 82 } 83 } 84 85 /// 86 unittest { 87 import bolts.range: isSortedRange; 88 89 struct A { // unsortable 90 int i; 91 } 92 93 struct B { // sortable 94 int i; 95 bool opCmp(B a) { 96 return i < a.i; 97 } 98 } 99 100 struct C { 101 B b; 102 A a; 103 } 104 105 static assert(!isSortedRange!([C()].maybeSortBy!"a")); 106 static assert( isSortedRange!([C()].maybeSortBy!"b")); 107 static assert( isSortedRange!([C()].maybeSortBy!("a", "a.i < b.i"))); 108 } 109 110 /** 111 Sorts a range using the standard library sort by a publicly visible member variable or property of `ElemntType!Range` 112 113 Since: 114 0.0.1 115 */ 116 auto sortBy(string member, alias less = "a < b", Range)(Range range) { 117 import std.algorithm: stdSort = sort; 118 import std.functional: binaryFun; 119 import ddash.common.valueby; 120 return range.stdSort!((a, b) => binaryFun!less(valueBy!member(a), valueBy!member(b))); 121 } 122 123 /// 124 unittest { 125 struct A { 126 int i; 127 } 128 auto a = [A(3), A(1), A(2)]; 129 assert(a.sortBy!"i".equal([A(1), A(2), A(3)])); 130 }