Merge pull request #2898 from quickfur/topNIndex

Move topNIndex to std.algorithm.sorting.
This commit is contained in:
Andrei Alexandrescu 2015-01-23 12:16:43 -08:00
commit ed3776a8c7
2 changed files with 142 additions and 83 deletions

View file

@ -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)
{ {

View file

@ -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