mirror of
https://github.com/dlang/phobos.git
synced 2025-04-29 22:50:38 +03:00
Merge pull request #2898 from quickfur/topNIndex
Move topNIndex to std.algorithm.sorting.
This commit is contained in:
commit
ed3776a8c7
2 changed files with 142 additions and 83 deletions
|
@ -90,6 +90,7 @@ $(TR $(TDNW Sorting)
|
||||||
$(SUBREF sorting, sort)
|
$(SUBREF sorting, sort)
|
||||||
$(SUBREF sorting, topN)
|
$(SUBREF sorting, topN)
|
||||||
$(SUBREF sorting, topNCopy)
|
$(SUBREF sorting, topNCopy)
|
||||||
|
$(SUBREF sorting, topNIndex)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
$(TR $(TDNW Set operations)
|
$(TR $(TDNW Set operations)
|
||||||
|
@ -309,82 +310,6 @@ enum SortOutput
|
||||||
yes, /// Sort output
|
yes, /// Sort output
|
||||||
}
|
}
|
||||||
|
|
||||||
void topNIndex(
|
|
||||||
alias less = "a < b",
|
|
||||||
SwapStrategy ss = SwapStrategy.unstable,
|
|
||||||
Range, RangeIndex)(Range r, RangeIndex index, SortOutput sorted = SortOutput.no)
|
|
||||||
if (isIntegral!(ElementType!(RangeIndex)))
|
|
||||||
{
|
|
||||||
import std.container : BinaryHeap;
|
|
||||||
import std.exception : enforce;
|
|
||||||
|
|
||||||
if (index.empty) return;
|
|
||||||
enforce(ElementType!(RangeIndex).max >= index.length,
|
|
||||||
"Index type too small");
|
|
||||||
bool indirectLess(ElementType!(RangeIndex) a, ElementType!(RangeIndex) b)
|
|
||||||
{
|
|
||||||
return binaryFun!(less)(r[a], r[b]);
|
|
||||||
}
|
|
||||||
auto heap = BinaryHeap!(RangeIndex, indirectLess)(index, 0);
|
|
||||||
foreach (i; 0 .. r.length)
|
|
||||||
{
|
|
||||||
heap.conditionalInsert(cast(ElementType!RangeIndex) i);
|
|
||||||
}
|
|
||||||
if (sorted == SortOutput.yes)
|
|
||||||
{
|
|
||||||
while (!heap.empty) heap.removeFront();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void topNIndex(
|
|
||||||
alias less = "a < b",
|
|
||||||
SwapStrategy ss = SwapStrategy.unstable,
|
|
||||||
Range, RangeIndex)(Range r, RangeIndex index,
|
|
||||||
SortOutput sorted = SortOutput.no)
|
|
||||||
if (is(ElementType!(RangeIndex) == ElementType!(Range)*))
|
|
||||||
{
|
|
||||||
import std.container : BinaryHeap;
|
|
||||||
|
|
||||||
if (index.empty) return;
|
|
||||||
static bool indirectLess(const ElementType!(RangeIndex) a,
|
|
||||||
const ElementType!(RangeIndex) b)
|
|
||||||
{
|
|
||||||
return binaryFun!less(*a, *b);
|
|
||||||
}
|
|
||||||
auto heap = BinaryHeap!(RangeIndex, indirectLess)(index, 0);
|
|
||||||
foreach (i; 0 .. r.length)
|
|
||||||
{
|
|
||||||
heap.conditionalInsert(&r[i]);
|
|
||||||
}
|
|
||||||
if (sorted == SortOutput.yes)
|
|
||||||
{
|
|
||||||
while (!heap.empty) heap.removeFront();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unittest
|
|
||||||
{
|
|
||||||
import std.conv : text;
|
|
||||||
|
|
||||||
debug(std_algorithm) scope(success)
|
|
||||||
writeln("unittest @", __FILE__, ":", __LINE__, " done.");
|
|
||||||
|
|
||||||
{
|
|
||||||
int[] a = [ 10, 8, 9, 2, 4, 6, 7, 1, 3, 5 ];
|
|
||||||
int*[] b = new int*[5];
|
|
||||||
topNIndex!("a > b")(a, b, SortOutput.yes);
|
|
||||||
//foreach (e; b) writeln(*e);
|
|
||||||
assert(b == [ &a[0], &a[2], &a[1], &a[6], &a[5]]);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
int[] a = [ 10, 8, 9, 2, 4, 6, 7, 1, 3, 5 ];
|
|
||||||
auto b = new ubyte[5];
|
|
||||||
topNIndex!("a > b")(a, b, SortOutput.yes);
|
|
||||||
//foreach (e; b) writeln(e, ":", a[e]);
|
|
||||||
assert(b == [ cast(ubyte) 0, cast(ubyte)2, cast(ubyte)1, cast(ubyte)6, cast(ubyte)5], text(b));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Internal random array generators
|
// Internal random array generators
|
||||||
version(unittest)
|
version(unittest)
|
||||||
{
|
{
|
||||||
|
|
|
@ -44,6 +44,8 @@ $(T2 topN,
|
||||||
Separates the top elements in a range.)
|
Separates the top elements in a range.)
|
||||||
$(T2 topNCopy,
|
$(T2 topNCopy,
|
||||||
Copies out the top elements of a range.)
|
Copies out the top elements of a range.)
|
||||||
|
$(T2 topNIndex,
|
||||||
|
Builds an index of the top elements of a range.)
|
||||||
)
|
)
|
||||||
|
|
||||||
Copyright: Andrei Alexandrescu 2008-.
|
Copyright: Andrei Alexandrescu 2008-.
|
||||||
|
@ -1001,7 +1003,7 @@ unittest
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
import std.algorithm : swap; // FIXME
|
import std.algorithm : swap; // FIXME
|
||||||
|
|
||||||
bool proxySwapCalled;
|
bool proxySwapCalled;
|
||||||
struct S
|
struct S
|
||||||
|
@ -1174,7 +1176,7 @@ private template TimSortImpl(alias pred, R)
|
||||||
// Entry point for tim sort
|
// Entry point for tim sort
|
||||||
void sort(R range, T[] temp)
|
void sort(R range, T[] temp)
|
||||||
{
|
{
|
||||||
import std.algorithm.comparison : min;
|
import std.algorithm.comparison : min;
|
||||||
|
|
||||||
// Do insertion sort on small range
|
// Do insertion sort on small range
|
||||||
if (range.length <= minimalMerge)
|
if (range.length <= minimalMerge)
|
||||||
|
@ -1267,7 +1269,7 @@ private template TimSortImpl(alias pred, R)
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
import std.algorithm : reverse; // FIXME
|
import std.algorithm : reverse; // FIXME
|
||||||
|
|
||||||
if (range.length < 2) return range.length;
|
if (range.length < 2) return range.length;
|
||||||
|
|
||||||
|
@ -1292,7 +1294,7 @@ private template TimSortImpl(alias pred, R)
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
import std.algorithm : move; // FIXME
|
import std.algorithm : move; // FIXME
|
||||||
|
|
||||||
for (; sortedLen < range.length; ++sortedLen)
|
for (; sortedLen < range.length; ++sortedLen)
|
||||||
{
|
{
|
||||||
|
@ -1402,7 +1404,7 @@ private template TimSortImpl(alias pred, R)
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
import std.algorithm : copy; // FIXME
|
import std.algorithm : copy; // FIXME
|
||||||
|
|
||||||
assert(mid <= range.length);
|
assert(mid <= range.length);
|
||||||
assert(temp.length >= mid);
|
assert(temp.length >= mid);
|
||||||
|
@ -1485,7 +1487,7 @@ private template TimSortImpl(alias pred, R)
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
import std.algorithm : copy; // FIXME
|
import std.algorithm : copy; // FIXME
|
||||||
|
|
||||||
assert(mid <= range.length);
|
assert(mid <= range.length);
|
||||||
assert(temp.length >= range.length - mid);
|
assert(temp.length >= range.length - mid);
|
||||||
|
@ -1674,7 +1676,7 @@ unittest
|
||||||
// Generates data especially for testing sorting with Timsort
|
// Generates data especially for testing sorting with Timsort
|
||||||
static E[] genSampleData(uint seed)
|
static E[] genSampleData(uint seed)
|
||||||
{
|
{
|
||||||
import std.algorithm : swap, swapRanges; // FIXME
|
import std.algorithm : swap, swapRanges; // FIXME
|
||||||
|
|
||||||
auto rnd = Random(seed);
|
auto rnd = Random(seed);
|
||||||
|
|
||||||
|
@ -1957,6 +1959,7 @@ $(BIGOH r.length) (if unstable) or $(BIGOH r.length * log(r.length))
|
||||||
If $(D n >= r.length), the algorithm has no effect.
|
If $(D n >= r.length), the algorithm has no effect.
|
||||||
|
|
||||||
See_Also:
|
See_Also:
|
||||||
|
$(LREF topNIndex),
|
||||||
$(WEB sgi.com/tech/stl/nth_element.html, STL's nth_element)
|
$(WEB sgi.com/tech/stl/nth_element.html, STL's nth_element)
|
||||||
|
|
||||||
BUGS:
|
BUGS:
|
||||||
|
@ -2166,6 +2169,137 @@ unittest
|
||||||
assert(isSorted!(binaryFun!("a < b"))(b));
|
assert(isSorted!(binaryFun!("a < b"))(b));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Given a range of elements, constructs an index of its top $(I n) elements
|
||||||
|
(i.e., the first $(I n) elements if the range were sorted).
|
||||||
|
|
||||||
|
Similar to $(LREF topN), except that the range is not modified.
|
||||||
|
|
||||||
|
Params:
|
||||||
|
less = A binary predicate that defines the ordering of range elements.
|
||||||
|
Defaults to $(D a < b).
|
||||||
|
ss = $(RED (Not implemented yet.)) Specify the swapping strategy.
|
||||||
|
r = A $(XREF2 range, isRandomAccessRange, random-access range) of elements
|
||||||
|
to make an index for.
|
||||||
|
index = A $(XREF2 range, isRandomAccessRange, random-access range) with
|
||||||
|
assignable elements to build the index in. The length of this range
|
||||||
|
determines how many top elements to index in $(D r).
|
||||||
|
|
||||||
|
This index range can either have integral elements, in which case the
|
||||||
|
constructed index will consist of zero-based numerical indices into
|
||||||
|
$(D r); or it can have pointers to the element type of $(D r), in which
|
||||||
|
case the constructed index will be pointers to the top elements in
|
||||||
|
$(D r).
|
||||||
|
sorted = Determines whether to sort the index by the elements they refer
|
||||||
|
to.
|
||||||
|
|
||||||
|
See_also: $(LREF topN), $(LREF topNCopy).
|
||||||
|
|
||||||
|
BUGS:
|
||||||
|
The swapping strategy parameter is not implemented yet; currently it is
|
||||||
|
ignored.
|
||||||
|
*/
|
||||||
|
void topNIndex(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable,
|
||||||
|
Range, RangeIndex)
|
||||||
|
(Range r, RangeIndex index, SortOutput sorted = SortOutput.no)
|
||||||
|
if (isRandomAccessRange!Range &&
|
||||||
|
isRandomAccessRange!RangeIndex &&
|
||||||
|
hasAssignableElements!RangeIndex &&
|
||||||
|
isIntegral!(ElementType!(RangeIndex)))
|
||||||
|
{
|
||||||
|
static assert(ss == SwapStrategy.unstable,
|
||||||
|
"Stable swap strategy not implemented yet.");
|
||||||
|
|
||||||
|
import std.container : BinaryHeap;
|
||||||
|
import std.exception : enforce;
|
||||||
|
|
||||||
|
if (index.empty) return;
|
||||||
|
enforce(ElementType!(RangeIndex).max >= index.length,
|
||||||
|
"Index type too small");
|
||||||
|
bool indirectLess(ElementType!(RangeIndex) a, ElementType!(RangeIndex) b)
|
||||||
|
{
|
||||||
|
return binaryFun!(less)(r[a], r[b]);
|
||||||
|
}
|
||||||
|
auto heap = BinaryHeap!(RangeIndex, indirectLess)(index, 0);
|
||||||
|
foreach (i; 0 .. r.length)
|
||||||
|
{
|
||||||
|
heap.conditionalInsert(cast(ElementType!RangeIndex) i);
|
||||||
|
}
|
||||||
|
if (sorted == SortOutput.yes)
|
||||||
|
{
|
||||||
|
while (!heap.empty) heap.removeFront();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ditto
|
||||||
|
void topNIndex(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable,
|
||||||
|
Range, RangeIndex)
|
||||||
|
(Range r, RangeIndex index, SortOutput sorted = SortOutput.no)
|
||||||
|
if (isRandomAccessRange!Range &&
|
||||||
|
isRandomAccessRange!RangeIndex &&
|
||||||
|
hasAssignableElements!RangeIndex &&
|
||||||
|
is(ElementType!(RangeIndex) == ElementType!(Range)*))
|
||||||
|
{
|
||||||
|
static assert(ss == SwapStrategy.unstable,
|
||||||
|
"Stable swap strategy not implemented yet.");
|
||||||
|
|
||||||
|
import std.container : BinaryHeap;
|
||||||
|
|
||||||
|
if (index.empty) return;
|
||||||
|
static bool indirectLess(const ElementType!(RangeIndex) a,
|
||||||
|
const ElementType!(RangeIndex) b)
|
||||||
|
{
|
||||||
|
return binaryFun!less(*a, *b);
|
||||||
|
}
|
||||||
|
auto heap = BinaryHeap!(RangeIndex, indirectLess)(index, 0);
|
||||||
|
foreach (i; 0 .. r.length)
|
||||||
|
{
|
||||||
|
heap.conditionalInsert(&r[i]);
|
||||||
|
}
|
||||||
|
if (sorted == SortOutput.yes)
|
||||||
|
{
|
||||||
|
while (!heap.empty) heap.removeFront();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
// 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, SortOutput.yes);
|
||||||
|
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, SortOutput.yes);
|
||||||
|
assert(ptrIndex == [ &a[5], &a[1], &a[3] ]);
|
||||||
|
}
|
||||||
|
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
import std.conv : text;
|
||||||
|
|
||||||
|
debug(std_algorithm) scope(success)
|
||||||
|
writeln("unittest @", __FILE__, ":", __LINE__, " done.");
|
||||||
|
|
||||||
|
{
|
||||||
|
int[] a = [ 10, 8, 9, 2, 4, 6, 7, 1, 3, 5 ];
|
||||||
|
int*[] b = new int*[5];
|
||||||
|
topNIndex!("a > b")(a, b, SortOutput.yes);
|
||||||
|
//foreach (e; b) writeln(*e);
|
||||||
|
assert(b == [ &a[0], &a[2], &a[1], &a[6], &a[5]]);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int[] a = [ 10, 8, 9, 2, 4, 6, 7, 1, 3, 5 ];
|
||||||
|
auto b = new ubyte[5];
|
||||||
|
topNIndex!("a > b")(a, b, SortOutput.yes);
|
||||||
|
//foreach (e; b) writeln(e, ":", a[e]);
|
||||||
|
assert(b == [ cast(ubyte) 0, cast(ubyte)2, cast(ubyte)1, cast(ubyte)6, cast(ubyte)5], text(b));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// nextPermutation
|
// nextPermutation
|
||||||
/**
|
/**
|
||||||
* Permutes $(D range) in-place to the next lexicographically greater
|
* Permutes $(D range) in-place to the next lexicographically greater
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue