std.algorithm.sorting
| Function Name | Description |
|---|---|
| completeSort | If a = [10, 20, 30] and b = [40, 6, 15], then completeSort(a, b) leaves a = [6, 10, 15] and b = [20, 30, 40]. The range a must be sorted prior to the call, and as a result the combination std.range.chain(a, b) is sorted. |
| isPartitioned | isPartitioned!"a < 0"([-1, -2, 1, 0, 2]) returns true because
the predicate is true for a portion of the range and false
afterwards. |
| isSorted | isSorted([1, 1, 2, 3]) returns true. |
| isStrictlyMonotonic | isStrictlyMonotonic([1, 1, 2, 3]) returns false. |
| ordered | ordered(1, 1, 2, 3) returns true. |
| strictlyOrdered | strictlyOrdered(1, 1, 2, 3) returns false. |
| makeIndex | Creates a separate index for a range. |
| merge | Lazily merges two or more sorted ranges. |
| multiSort | Sorts by multiple keys. |
| nextEvenPermutation | Computes the next lexicographically greater even permutation of a range in-place. |
| nextPermutation | Computes the next lexicographically greater permutation of a range in-place. |
| partialSort | If a = [5, 4, 3, 2, 1], then partialSort(a, 3) leaves a[0 .. 3] = [1, 2, 3]. The other elements of a are left in an unspecified order. |
| partition | Partitions a range according to a unary predicate. |
| partition3 | Partitions a range according to a binary predicate in three parts (less than, equal, greater than the given pivot). Pivot is not given as an index, but instead as an element independent from the range's content. |
| pivotPartition | Partitions a range according to a binary predicate in two parts: less than or equal, and greater than or equal to the given pivot, passed as an index in the range. |
| schwartzSort | Sorts with the help of the Schwartzian transform. |
| sort | Sorts. |
| topN | Separates the top elements in a range. |
| topNCopy | Copies out the top elements of a range. |
| topNIndex | Builds an index of the top elements of a range. |
Source: std/algorithm/sorting.d
- alias
SortOutput= std.typecons.Flag!"sortOutput".Flag; - Specifies whether the output of certain algorithm is desired in sorted format.If set to
SortOutput.no, the output should not be sorted. Otherwise if set toSortOutput.yes, the output should be sorted. - void
completeSort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, RandomAccessRange1, RandomAccessRange2)(SortedRange!(RandomAccessRange1, less)lhs, RandomAccessRange2rhs)
if (hasLength!RandomAccessRange2 && hasSlicing!RandomAccessRange2); - Sorts the random-access range chain(
lhs,rhs) according to predicate less. The left-hand side of the rangelhsis assumed to be already sorted;rhsis assumed to be unsorted. The exact strategy chosen depends on the relative sizes oflhsandrhs. Performs Ο(lhs.length +rhs.length * log(rhs.length)) (best case) to Ο((lhs.length +rhs.length) * log(lhs.length +rhs.length)) (worst-case) evaluations of swap.Parameters:less The predicate to sort by. ss The swapping strategy to use. SortedRange!(RandomAccessRange1, less) lhsThe sorted, left-hand side of the random access range to be sorted. RandomAccessRange2 rhsThe unsorted, right-hand side of the random access range to be sorted. Examples:import std.range : assumeSorted; int[] a = [ 1, 2, 3 ]; int[] b = [ 4, 0, 6, 5 ]; completeSort(assumeSorted(a), b); assert(a == [ 0, 1, 2 ]); assert(b == [ 3, 4, 5, 6 ]);
- bool
isSorted(alias less = "a < b", Range)(Ranger)
if (isForwardRange!Range);
boolisStrictlyMonotonic(alias less = "a < b", Range)(Ranger)
if (isForwardRange!Range); - Checks whether a forward range is sorted according to the comparison operation less. Performs Ο(
r.length) evaluations of less.UnlikeisSorted,isStrictlyMonotonicdoes not allow for equal values, i.e. values for which both less(a, b) and less(b, a) arefalse. With either function, the predicate must be a strict ordering just like withisSorted. For example, using "a <= b" instead of "a < b" is incorrect and will cause failed assertions.Parameters:less Predicate the range should be sorted by. Range rForward range to check for sortedness. Returns:true if the range is sorted,falseotherwise.isSortedallows duplicates,isStrictlyMonotonicnot.Examples:assert([1, 1, 2].isSorted); // strictly monotonic doesn't allow duplicates assert(![1, 1, 2].isStrictlyMonotonic); int[] arr = [4, 3, 2, 1]; assert(!isSorted(arr)); assert(!isStrictlyMonotonic(arr)); assert(isSorted!"a > b"(arr)); assert(isStrictlyMonotonic!"a > b"(arr)); sort(arr); assert(isSorted(arr)); assert(isStrictlyMonotonic(arr));
- bool
ordered(alias less = "a < b", T...)(Tvalues)
if (T.length == 2 && is(typeof(binaryFun!less(values[1],values[0])) : bool) || T.length > 2 && is(typeof(ordered!less(values[0..1 + $ / 2]))) && is(typeof(ordered!less(values[$ / 2..$]))));
boolstrictlyOrdered(alias less = "a < b", T...)(Tvalues)
if (is(typeof(ordered!less(values)))); - Like isSorted, returns
trueif the givenvaluesareorderedaccording to the comparison operation less. Unlike isSorted, takesvaluesdirectly instead of structured in a range.orderedallows repeatedvalues, e.g.ordered(1, 1, 2) istrue. To verify that thevaluesareorderedstrictly monotonically, usestrictlyOrdered;strictlyOrdered(1, 1, 2) isfalse. With either function, the predicate must be a strict ordering. For example, using "a <= b" instead of "a < b" is incorrect and will cause failed assertions.Parameters:T valuesThe tested value less The comparison predicate Returns:trueif thevaluesareordered;orderedallows for duplicates,strictlyOrdereddoes not.Examples:assert(ordered(42, 42, 43)); assert(!strictlyOrdered(43, 42, 45)); assert(ordered(42, 42, 43)); assert(!strictlyOrdered(42, 42, 43)); assert(!ordered(43, 42, 45)); // Ordered lexicographically assert(ordered("Jane", "Jim", "Joe")); assert(strictlyOrdered("Jane", "Jim", "Joe")); // Incidentally also ordered by length decreasing assert(ordered!((a, b) => a.length > b.length)("Jane", "Jim", "Joe")); // ... but not strictly so: "Jim" and "Joe" have the same length assert(!strictlyOrdered!((a, b) => a.length > b.length)("Jane", "Jim", "Joe"));
- Range
partition(alias predicate, SwapStrategy ss, Range)(Ranger)
if (ss == SwapStrategy.stable && isRandomAccessRange!Range && hasLength!Range && hasSlicing!Range);
Rangepartition(alias predicate, SwapStrategy ss = SwapStrategy.unstable, Range)(Ranger)
if (ss != SwapStrategy.stable && isInputRange!Range && hasSwappableElements!Range); - Partitions a range in two using the given predicate. Specifically, reorders the range
r= [left, right) using swap such that all elements i for which predicate(i) istruecome before all elements j for which predicate(j) returnsfalse.Performs Ο(r.length) (if unstable or semistable) or Ο(r.length * log(r.length)) (if stable) evaluations of less and swap. The unstable version computes the minimum possible evaluations of swap (roughly half of those performed by the semistable version).Parameters:predicate The predicate to partitionby.ss The swapping strategy to employ. Range rThe random-access range to partition.Returns:The right part ofrafter partitioning. If ss == SwapStrategy.stable,partitionpreserves the relative ordering of all elements a, b inrfor which predicate(a) == predicate(b). If ss == SwapStrategy.semistable,partitionpreserves the relative ordering of all elements a, b in the left part ofrfor which predicate(a) == predicate(b).See Also:Examples:import std.algorithm.searching : count, find; import std.conv : text; import std.range.primitives : empty; import std.algorithm.mutation : SwapStrategy; auto Arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; auto arr = Arr.dup; static bool even(int a) { return (a & 1) == 0; } // Partition arr such that even numbers come first auto r = partition!(even)(arr); // Now arr is separated in evens and odds. // Numbers may have become shuffled due to instability assert(r == arr[5 .. $]); assert(count!(even)(arr[0 .. 5]) == 5); assert(find!(even)(r).empty); // Can also specify the predicate as a string. // Use 'a' as the predicate argument name arr[] = Arr[]; r = partition!(q{(a & 1) == 0})(arr); assert(r == arr[5 .. $]); // Now for a stable partition: arr[] = Arr[]; r = partition!(q{(a & 1) == 0}, SwapStrategy.stable)(arr); // Now arr is [2 4 6 8 10 1 3 5 7 9], and r points to 1 assert(arr == [2, 4, 6, 8, 10, 1, 3, 5, 7, 9] && r == arr[5 .. $]); // In case the predicate needs to hold its own state, use a delegate: arr[] = Arr[]; int x = 3; // Put stuff greater than 3 on the left bool fun(int a) { return a > x; } r = partition!(fun, SwapStrategy.semistable)(arr); // Now arr is [4 5 6 7 8 9 10 2 3 1] and r points to 2 assert(arr == [4, 5, 6, 7, 8, 9, 10, 2, 3, 1] && r == arr[7 .. $]);
- size_t
pivotPartition(alias less = "a < b", Range)(Ranger, size_tpivot)
if (isRandomAccessRange!Range && hasLength!Range && hasSlicing!Range); - Partitions
raroundpivotusing comparison function less, algorithm akin to Hoare partition. Specifically, permutes elements ofrand returns an index k <r.length such that:r[pivot] is swapped tor[k]- All elements e in subrange
r[0 .. k] satisfy !less(r[k], e) (i.e.r[k] is greater than or equal to each element to its left according to predicate less) - All elements e in subrange
r[0 .. k] satisfy !less(e,r[k]) (i.e.r[k] is less than or equal to each element to its right according to predicate less)
rcontains equivalent elements, multiple permutations ofrsatisfy these constraints. In such cases,pivotPartitionattempts to distribute equivalent elements fairly to the left and right of k such that k stays close tor.length / 2.Parameters:less The predicate used for comparison, modeled as a strict weak ordering (irreflexive, antisymmetric, transitive, and implying a transitive equivalence) Range rThe range being partitioned size_t pivotThe index of the pivotfor partitioning, must be less thanr.length or 0 isr.length is 0Returns:The new position of thepivotSee Also:Engineering of a Quicksort Partitioning Algorithm, D. Abhyankar, Journal of Global Research in Computer Science, February 2011. ACCU 2016 Keynote, Andrei Alexandrescu.Examples:int[] a = [5, 3, 2, 6, 4, 1, 3, 7]; size_t pivot = pivotPartition(a, a.length / 2); import std.algorithm.searching : all; assert(a[0 .. pivot].all!(x => x <= a[pivot])); assert(a[pivot .. $].all!(x => x >= a[pivot]));
- bool
isPartitioned(alias pred, Range)(Ranger)
if (isForwardRange!Range); - Parameters:
pred The predicate that the range should be partitioned by. Range rThe range to check. Returns:trueifris partitioned according to predicate pred.Examples:int[] r = [ 1, 3, 5, 7, 8, 2, 4, ]; assert(isPartitioned!"a & 1"(r));
- auto
partition3(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range, E)(Ranger, Epivot)
if (ss == SwapStrategy.unstable && isRandomAccessRange!Range && hasSwappableElements!Range && hasLength!Range && hasSlicing!Range && is(typeof(binaryFun!less(r.front,pivot)) == bool) && is(typeof(binaryFun!less(pivot,r.front)) == bool) && is(typeof(binaryFun!less(r.front,r.front)) == bool)); - Rearranges elements in
rin three adjacent ranges and returns them. The first and leftmost range only contains elements inrless thanpivot. The second and middle range only contains elements inrthat are equal topivot. Finally, the third and rightmost range only contains elements inrthat are greater thanpivot. The less-than test is defined by the binary function less.Parameters:less The predicate to use for the rearrangement. ss The swapping strategy to use. Range rThe random-access range to rearrange. E pivotThe pivotelement.Returns:A std.typecons.Tuple of the three resulting ranges. These ranges are slices of the original range.Bugs:stablepartition3has not been implemented yet.Examples:auto a = [ 8, 3, 4, 1, 4, 7, 4 ]; auto pieces = partition3(a, 4); assert(pieces[0] == [ 1, 3 ]); assert(pieces[1] == [ 4, 4, 4 ]); assert(pieces[2] == [ 8, 7 ]);
- SortedRange!(RangeIndex, (a, b) => binaryFun!less(*a, *b))
makeIndex(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range, RangeIndex)(Ranger, RangeIndexindex)
if (isForwardRange!Range && isRandomAccessRange!RangeIndex && is(ElementType!RangeIndex : ElementType!Range*));
voidmakeIndex(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range, RangeIndex)(Ranger, RangeIndexindex)
if (isRandomAccessRange!Range && !isInfinite!Range && isRandomAccessRange!RangeIndex && !isInfinite!RangeIndex && isIntegral!(ElementType!RangeIndex)); - Computes an
indexforrbased on the comparison less. Theindexis a sorted array of pointers or indices into the original range. This technique is similar to sorting, but it is more flexible because (1) it allows "sorting" of immutable collections, (2) allows binary search even if the original collection does not offer random access, (3) allows multiple indexes, each on a different predicate, and (4) may be faster when dealing with large objects. However, using anindexmay also be slower under certain circumstances due to the extra indirection, and is always larger than a sorting-based solution because it needs space for theindexin addition to the original collection. The complexity is the same as sort's.The first overload ofmakeIndexwrites to a range containing pointers, and the second writes to a range containing offsets. The first overload requires Range to be a forward range, and the latter requires it to be a random-access range.makeIndexoverwrites its second argument with the result, but never reallocates it.Parameters:less The comparison to use. ss The swapping strategy. Range rThe range to index.RangeIndex indexThe resulting index.Returns:The pointer-based version returns a SortedRange wrapper overindex, of type SortedRange!(RangeIndex, (a, b) => binaryFun!less(*a, *b)) thus reflecting the ordering of theindex. Theindex-based version returns void because the ordering relation involves not onlyindexbut alsor.Throws:If the second argument's length is less than that of the range indexed, an exception is thrown.Examples:immutable(int[]) arr = [ 2, 3, 1, 5, 0 ]; // index using pointers auto index1 = new immutable(int)*[arr.length]; makeIndex!("a < b")(arr, index1); assert(isSorted!("*a < *b")(index1)); // index using offsets auto index2 = new size_t[arr.length]; makeIndex!("a < b")(arr, index2); assert(isSorted! ((size_t a, size_t b){ return arr[a] < arr[b];}) (index2));
- Merge!(less, Rs)
merge(alias less = "a < b", Rs...)(Rsrs)
if (Rs.length >= 2 && allSatisfy!(isInputRange, Rs) && !is(CommonType!(staticMap!(ElementType, Rs)) == void)); - Merge multiple sorted ranges
rswith less-than predicate function pred into one single sorted output range containing the sorted union of the elements of inputs. Duplicates are not eliminated, meaning that the total number of elements in the output is the sum of all elements in the ranges passed to it; the length member is offered if all inputs also have length. The element types of all the inputs must have a common type CommonType.Parameters:less Predicate the given ranges are sorted by. Rs rsThe ranges to compute the union for. Returns:A range containing the union of the given ranges.Details: All of its inputs are assumed to be sorted. This can mean that inputs are instances of std.range.SortedRange. Use the result of std.algorithm.sorting.sort, or std.range.assumeSorted to
This algorithm is lazy, doing work progressively as elements are pulled off the result. Time complexity is proportional to the sum of element counts over all inputs. If all inputs have the same element type and offer it by ref, output becomes a range with mutable front (and back where appropriate) that reflects in the original inputs. If any of the inputsmergeranges known to be sorted (show in the example below). Note that there is currently no way of ensuring that two or more instances of std.range.SortedRange are sorted using a specific comparison function pred. Therefore no checking is done here to assure that all inputsrsare instances of std.range.SortedRange.rsis infinite so is the result (empty being always false).Examples:import std.algorithm.comparison : equal; import std.range : retro; int[] a = [1, 3, 5]; int[] b = [2, 3, 4]; assert(a.merge(b).equal([1, 2, 3, 3, 4, 5])); assert(a.merge(b).retro.equal([5, 4, 3, 3, 2, 1]));
Examples:test bi-directional access and common typeimport std.algorithm.comparison : equal; import std.range : retro; import std.traits : CommonType; alias S = short; alias I = int; alias D = double; S[] a = [1, 2, 3]; I[] b = [50, 60]; D[] c = [10, 20, 30, 40]; auto m = merge(a, b, c); static assert(is(typeof(m.front) == CommonType!(S, I, D))); assert(equal(m, [1, 2, 3, 10, 20, 30, 40, 50, 60])); assert(equal(m.retro, [60, 50, 40, 30, 20, 10, 3, 2, 1])); m.popFront(); assert(equal(m, [2, 3, 10, 20, 30, 40, 50, 60])); m.popBack(); assert(equal(m, [2, 3, 10, 20, 30, 40, 50])); m.popFront(); assert(equal(m, [3, 10, 20, 30, 40, 50])); m.popBack(); assert(equal(m, [3, 10, 20, 30, 40])); m.popFront(); assert(equal(m, [10, 20, 30, 40])); m.popBack(); assert(equal(m, [10, 20, 30])); m.popFront(); assert(equal(m, [20, 30])); m.popBack(); assert(equal(m, [20])); m.popFront(); assert(m.empty);
- template
multiSort(less...) - auto
multiSort(Range)(Range r) if (validPredicates!(ElementType!Range, less));Sorts a range by multiple keys. The callmultiSort!("a.id < b.id", "a.date > b.date")(r) sorts the range r by id ascending, and sorts elements that have the same id by date descending. Such a call is equivalent to sort!"a.id != b.id ? a.id < b.id : a.date > b.date"(r), butmultiSortis faster because it does fewer comparisons (in addition to being more convenient).Returns:The initial range wrapped as a SortedRange with its predicates converted to an equivalent single predicate. - SortedRange!(Range, less)
sort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range)(Ranger)
if ((ss == SwapStrategy.unstable && (hasSwappableElements!Range || hasAssignableElements!Range) || ss != SwapStrategy.unstable && hasAssignableElements!Range) && isRandomAccessRange!Range && hasSlicing!Range && hasLength!Range); - Sorts a random-access range according to the predicate less. Performs Ο(
r.length * log(r.length)) evaluations of less. If less involves expensive computations on the sort key, it may be worthwhile to use schwartzSort instead.Stable sorting requires hasAssignableElements!Range to betrue.sortreturns a std.range.SortedRange over the original range, allowing functions that can take advantage of sorted data to know that the range is sorted and adjust accordingly. The std.range.SortedRange is a wrapper around the original range, so both it and the original range are sorted. Other functions can't know that the original range has been sorted, but they can know that std.range.SortedRange has been sorted.Preconditions: The predicate is expected to satisfy certain rules in order for
sortto behave as expected - otherwise, the program may fail on certain inputs (but not others) when not compiled in release mode, due to the cursory assumeSorted check. Specifically,sortexpects less(a,b) && less(b,c) to imply less(a,c) (transitivity), and, conversely, !less(a,b) && !less(b,c) to imply !less(a,c). Note that the default predicate ("a < b") does not always satisfy these conditions for floating point types, because the expression will always befalsewhen either a or b is NaN. Use std.math.cmp instead.Parameters:less The predicate to sortby.ss The swapping strategy to use. Range rThe range to sort.Returns:The initial range wrapped as a SortedRange with the predicate binaryFun!less.Algorithms: Introsort is used for unstable sorting and Timsort is used for stable sorting. Each algorithm has benefits beyond stability. Introsort is generally faster but Timsort may achieve greater speeds on data with low entropy or if predicate calls are expensive. Introsort performs no allocations whereas Timsort will perform one or more allocations per call. Both algorithms have Ο(n log n) worst-case time complexity.
See Also:Examples:int[] array = [ 1, 2, 3, 4 ]; // sort in descending order array.sort!("a > b"); assert(array == [ 4, 3, 2, 1 ]); // sort in ascending order array.sort(); assert(array == [ 1, 2, 3, 4 ]); // sort with reusable comparator and chain alias myComp = (x, y) => x > y; assert(array.sort!(myComp).release == [ 4, 3, 2, 1 ]);
Examples:// Showcase stable sorting import std.algorithm.mutation : SwapStrategy; string[] words = [ "aBc", "a", "abc", "b", "ABC", "c" ]; sort!("toUpper(a) < toUpper(b)", SwapStrategy.stable)(words); assert(words == [ "a", "aBc", "abc", "ABC", "b", "c" ]);
Examples:// Sorting floating-point numbers in presence of NaN double[] numbers = [-0.0, 3.0, -2.0, double.nan, 0.0, -double.nan]; import std.math : cmp, isIdentical; import std.algorithm.comparison : equal; sort!((a, b) => cmp(a, b) < 0)(numbers); double[] sorted = [-double.nan, -2.0, -0.0, 0.0, 3.0, double.nan]; assert(numbers.equal!isIdentical(sorted));
- SortedRange!(R, (a, b) => binaryFun!less(unaryFun!transform(a), unaryFun!transform(b)))
schwartzSort(alias transform, alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, R)(Rr)
if (isRandomAccessRange!R && hasLength!R); - Alternative sorting method that should be used when comparing keys involves an expensive computation. Instead of using less(a, b) for comparing elements,
schwartzSortuses less(transform(a), transform(b)). The values of the transform function are precomputed in a temporary array, thus saving on repeatedly computing it. Conversely, if the cost of transform is small compared to the cost of allocating and filling the precomputed array, sort may be faster and therefore preferable.This approach to sorting is akin to the Schwartzian transform, also known as the decorate-sort-undecorate pattern in Python and Lisp. The complexity is the same as that of the corresponding sort, butschwartzSortevaluates transform onlyr.length times (less than half when compared to regular sorting). The usage can be best illustrated with an example.Example:
uint hashFun(string) { ... expensive computation ... } string[] array = ...; // Sort strings by hash, slow sort!((a, b) => hashFun(a) < hashFun(b))(array); // Sort strings by hash, fast (only computes arr.length hashes): schwartzSort!(hashFun, "a < b")(array);
TheschwartzSortfunction might require less temporary data and be faster than the Perl idiom or the decorate-sort-undecorate idiom present in Python and Lisp. This is because sorting is done in-place and only minimal extra data (one array of transformed elements) is created. To check whether an array was sorted and benefit of the speedup of Schwartz sorting, a function schwartzIsSorted is not provided because the effect can be achieved by calling isSorted!less(map!transform(r)).Parameters:transform The transformation to apply. less The predicate to sort by. ss The swapping strategy to use. R rThe range to sort. Returns:The initial range wrapped as a SortedRange with the predicate (a, b) => binaryFun!less(transform(a), transform(b)).Examples:import std.algorithm.iteration : map; import std.numeric : entropy; auto lowEnt = [ 1.0, 0, 0 ], midEnt = [ 0.1, 0.1, 0.8 ], highEnt = [ 0.31, 0.29, 0.4 ]; auto arr = new double[][3]; arr[0] = midEnt; arr[1] = lowEnt; arr[2] = highEnt; schwartzSort!(entropy, "a > b")(arr); assert(arr[0] == highEnt); assert(arr[1] == midEnt); assert(arr[2] == lowEnt); assert(isSorted!("a > b")(map!(entropy)(arr)));
- void
partialSort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range)(Ranger, size_tn)
if (isRandomAccessRange!Range && hasLength!Range && hasSlicing!Range); - Reorders the random-access range
rsuch that the ranger[0 .. mid] is the same as if the entirerwere sorted, and leaves the ranger[mid ..r.length] in no particular order. Performs Ο(r.length * log(mid)) evaluations of pred. The implementation simply calls topN!(less, ss)(r,n) and then sort!(less, ss)(r[0 ..n]).Parameters:less The predicate to sort by. ss The swapping strategy to use. Range rThe random-access range to reorder. size_t nThe length of the initial segment of rto sort.Examples:int[] a = [ 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 ]; partialSort(a, 5); assert(a[0 .. 5] == [ 0, 1, 2, 3, 4 ]);
- void
partialSort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range1, Range2)(Range1r1, Range2r2)
if (isRandomAccessRange!Range1 && hasLength!Range1 && isInputRange!Range2 && is(ElementType!Range1 == ElementType!Range2) && hasLvalueElements!Range1 && hasLvalueElements!Range2); - Stores the smallest elements of the two ranges in the left-hand range in sorted order.Parameters:
less The predicate to sort by. ss The swapping strategy to use. Range1 r1The first range. Range2 r2The second range. Examples:int[] a = [5, 7, 2, 6, 7]; int[] b = [2, 1, 5, 6, 7, 3, 0]; partialSort(a, b); assert(a == [0, 1, 2, 2, 3]);
- auto
topN(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range)(Ranger, size_tnth)
if (isRandomAccessRange!Range && hasLength!Range && hasSlicing!Range); - Reorders the range
rusing swap such thatr[nth] refers to the element that would fall there if the range were fully sorted. In addition, it also partitionsrsuch that all elements e1 fromr[0] tor[nth] satisfy !less(r[nth], e1), and all elements e2 fromr[nth] tor[r.length] satisfy !less(e2,r[nth]). Effectively, it finds thenthsmallest (according to less) elements inr. Performs an expected Ο(r.length) (if unstable) or Ο(r.length * log(r.length)) (if stable) evaluations of less and swap.If n >=r.length, the algorithm has no effect and returnsr[0 ..r.length].Parameters:less The predicate to sort by. ss The swapping strategy to use. Range rThe random-access range to reorder. size_t nthThe index of the element that should be in sorted position after the function is done. See Also:Bugs:StabletopNhas not been implemented yet. - auto
topN(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range1, Range2)(Range1r1, Range2r2)
if (isRandomAccessRange!Range1 && hasLength!Range1 && isInputRange!Range2 && is(ElementType!Range1 == ElementType!Range2) && hasLvalueElements!Range1 && hasLvalueElements!Range2); - Stores the smallest elements of the two ranges in the left-hand range.Parameters:
less The predicate to sort by. ss The swapping strategy to use. Range1 r1The first range. Range2 r2The second range. Examples:int[] a = [ 5, 7, 2, 6, 7 ]; int[] b = [ 2, 1, 5, 6, 7, 3, 0 ]; topN(a, b); sort(a); assert(a == [0, 1, 2, 2, 3]);
- TRange
topNCopy(alias less = "a < b", SRange, TRange)(SRangesource, TRangetarget, SortOutputsorted= No.sortOutput)
if (isInputRange!SRange && isRandomAccessRange!TRange && hasLength!TRange && hasSlicing!TRange); - Copies the top n elements of the input range
sourceinto the random-access rangetarget, where n =target.length. Elements ofsourceare not touched. Ifsortedistrue, thetargetissorted. Otherwise, thetargetrespects the heap property.Parameters:less The predicate to sort by. SRange sourceThe sourcerange.TRange targetThe targetrange.SortOutput sortedWhether to sort the elements copied into target.Returns:The slice oftargetcontaining the copied elements.Examples:import std.typecons : Yes; int[] a = [ 10, 16, 2, 3, 1, 5, 0 ]; int[] b = new int[3]; topNCopy(a, b, Yes.sortOutput); assert(b == [ 0, 1, 2 ]);
- void
topNIndex(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range, RangeIndex)(Ranger, RangeIndexindex, SortOutputsorted= No.sortOutput)
if (isRandomAccessRange!Range && isRandomAccessRange!RangeIndex && hasAssignableElements!RangeIndex && isIntegral!(ElementType!RangeIndex));
voidtopNIndex(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range, RangeIndex)(Ranger, RangeIndexindex, SortOutputsorted= No.sortOutput)
if (isRandomAccessRange!Range && isRandomAccessRange!RangeIndex && hasAssignableElements!RangeIndex && is(ElementType!RangeIndex == ElementType!Range*)); - Given a range of elements, constructs an
indexof its top n elements (i.e., the first n elements if the range weresorted).Similar to topN, except that the range is not modified.Parameters:less A binary predicate that defines the ordering of range elements. Defaults to a < b. ss (Not implemented yet.) Specify the swapping strategy. Range rA random-access range of elements to make an indexfor.RangeIndex indexA random-access range with assignable elements to build the indexin. The length of this range determines how many top elements toindexinr. Thisindexrange can either have integral elements, in which case the constructedindexwill consist of zero-based numerical indices intor; or it can have pointers to the element type ofr, in which case the constructedindexwill be pointers to the top elements inr.SortOutput sortedDetermines whether to sort the indexby the elements they refer to.Bugs:The swapping strategy parameter is not implemented yet; currently it is ignored.Examples:import std.typecons : Yes; // Construct index to top 3 elements using numerical indices: int[] a = [ 10, 2, 7, 5, 8, 1 ]; int[] index = new int[3]; topNIndex(a, index, Yes.sortOutput); assert(index == [5, 1, 3]); // because a[5]==1, a[1]==2, a[3]==5 // Construct index to top 3 elements using pointer indices: int*[] ptrIndex = new int*[3]; topNIndex(a, ptrIndex, Yes.sortOutput); assert(ptrIndex == [ &a[5], &a[1], &a[3] ]);
- bool
nextPermutation(alias less = "a < b", BidirectionalRange)(BidirectionalRangerange)
if (isBidirectionalRange!BidirectionalRange && hasSwappableElements!BidirectionalRange); - Permutes
rangein-place to the next lexicographically greater permutation.The predicate less defines the lexicographical ordering to be used on therange. If therangeis currently the lexicographically greatest permutation, it is permuted back to the least permutation andfalseis returned. Otherwise,trueis returned. One can thus generate all permutations of arangeby sorting it according to less, which produces the lexicographically least permutation, and then callingnextPermutationuntil it returnsfalse. This is guaranteed to generate all distinct permutations of therangeexactly once. If there are N elements in therangeand all of them are unique, then N! permutations will be generated. Otherwise, if there are some duplicated elements, fewer permutations will be produced.// Enumerate all permutations int[] a = [1,2,3,4,5]; do { // use the current permutation and // proceed to the next permutation of the array. } while (nextPermutation(a));
Parameters:less The ordering to be used to determine lexicographical ordering of the permutations. BidirectionalRange rangeThe rangeto permute.Returns:falseif therangewas lexicographically the greatest, in which case therangeis reversed back to the lexicographically smallest permutation; otherwise returnstrue.See Also:Examples:// Step through all permutations of a sorted array in lexicographic order int[] a = [1,2,3]; assert(nextPermutation(a) == true); assert(a == [1,3,2]); assert(nextPermutation(a) == true); assert(a == [2,1,3]); assert(nextPermutation(a) == true); assert(a == [2,3,1]); assert(nextPermutation(a) == true); assert(a == [3,1,2]); assert(nextPermutation(a) == true); assert(a == [3,2,1]); assert(nextPermutation(a) == false); assert(a == [1,2,3]);
Examples:// Step through permutations of an array containing duplicate elements: int[] a = [1,1,2]; assert(nextPermutation(a) == true); assert(a == [1,2,1]); assert(nextPermutation(a) == true); assert(a == [2,1,1]); assert(nextPermutation(a) == false); assert(a == [1,1,2]);
- bool
nextEvenPermutation(alias less = "a < b", BidirectionalRange)(BidirectionalRangerange)
if (isBidirectionalRange!BidirectionalRange && hasSwappableElements!BidirectionalRange); - Permutes
rangein-place to the next lexicographically greater even permutation.The predicate less defines the lexicographical ordering to be used on therange. An even permutation is one which is produced by swapping an even number of pairs of elements in the originalrange. The set of even permutations is distinct from the set of all permutations only when there are no duplicate elements in therange. If therangehas N unique elements, then there are exactly N!/2 even permutations. If therangeis already the lexicographically greatest even permutation, it is permuted back to the least even permutation andfalseis returned. Otherwise,trueis returned, and therangeis modified in-place to be the lexicographically next even permutation. One can thus generate the even permutations of arangewith unique elements by starting with the lexicographically smallest permutation, and repeatedly callingnextEvenPermutationuntil it returnsfalse.// Enumerate even permutations int[] a = [1,2,3,4,5]; do { // use the current permutation and // proceed to the next even permutation of the array. } while (nextEvenPermutation(a));
One can also generate the odd permutations of arangeby noting that permutations obey the rule that even + even = even, and odd + even = odd. Thus, by swapping the last two elements of a lexicographically leastrange, it is turned into the first odd permutation. Then callingnextEvenPermutationon this first odd permutation will generate the next even permutation relative to this odd permutation, which is actually the next odd permutation of the originalrange. Thus, by repeatedly callingnextEvenPermutationuntil it returnsfalse, one enumerates the odd permutations of the originalrange.// Enumerate odd permutations int[] a = [1,2,3,4,5]; swap(a[$-2], a[$-1]); // a is now the first odd permutation of [1,2,3,4,5] do { // use the current permutation and // proceed to the next odd permutation of the original array // (which is an even permutation of the first odd permutation). } while (nextEvenPermutation(a));
Warning: Since even permutations are only distinct from all permutations when the
rangeelements are unique, this function assumes that there are no duplicate elements under the specified ordering. If this is not true, some permutations may fail to be generated. When therangehas non-unique elements, you should use nextPermutation instead.Parameters:less The ordering to be used to determine lexicographical ordering of the permutations. BidirectionalRange rangeThe rangeto permute.Returns:falseif therangewas lexicographically the greatest, in which case therangeis reversed back to the lexicographically smallest permutation; otherwise returnstrue.Examples:// Step through even permutations of a sorted array in lexicographic order int[] a = [1,2,3]; assert(nextEvenPermutation(a) == true); assert(a == [2,3,1]); assert(nextEvenPermutation(a) == true); assert(a == [3,1,2]); assert(nextEvenPermutation(a) == false); assert(a == [1,2,3]);
Examples:Even permutations are useful for generating coordinates of certain geometric shapes. Here's a non-trivial example:import std.math : sqrt; // Print the 60 vertices of a uniform truncated icosahedron (soccer ball) enum real Phi = (1.0 + sqrt(5.0)) / 2.0; // Golden ratio real[][] seeds = [ [0.0, 1.0, 3.0*Phi], [1.0, 2.0+Phi, 2.0*Phi], [Phi, 2.0, Phi^^3] ]; size_t n; foreach (seed; seeds) { // Loop over even permutations of each seed do { // Loop over all sign changes of each permutation size_t i; do { // Generate all possible sign changes for (i=0; i < seed.length; i++) { if (seed[i] != 0.0) { seed[i] = -seed[i]; if (seed[i] < 0.0) break; } } n++; } while (i < seed.length); } while (nextEvenPermutation(seed)); } assert(n == 60);