Skip to content

Commit d10b99a

Browse files
Fix nthPermutation lexicographic order
Fix Bugzilla issue 10849
1 parent f7249cf commit d10b99a

File tree

1 file changed

+53
-4
lines changed

1 file changed

+53
-4
lines changed

std/algorithm/sorting.d

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ T2=$(TR $(TDNW $(LREF $1)) $(TD $+))
7777
*/
7878
module std.algorithm.sorting;
7979

80-
import std.algorithm.mutation : SwapStrategy;
80+
import std.algorithm.mutation : SwapStrategy, reverse;
8181
import std.functional : unaryFun, binaryFun;
8282
import std.range.primitives;
8383
import std.typecons : Flag, No, Yes;
@@ -5025,6 +5025,8 @@ bool nthPermutationImpl(Range)
50255025
(auto ref Range range, ulong perm)
50265026
if (isRandomAccessRange!Range && hasLength!Range)
50275027
{
5028+
5029+
50285030
import std.range.primitives : ElementType;
50295031
import std.numeric : decimalToFactorial;
50305032

@@ -5037,10 +5039,22 @@ if (isRandomAccessRange!Range && hasLength!Range)
50375039
return false;
50385040
}
50395041

5042+
if (idx < range.length)
5043+
{
5044+
reverse(fac[0 .. idx]);
5045+
5046+
// Preserve leading zero digits in the Lehmer code to ensure lexicographic order
5047+
5048+
reverse(fac[0 .. range.length]);
5049+
}
5050+
5051+
5052+
size_t len = range.length;
5053+
50405054
ElementType!Range tmp;
50415055
size_t i = 0;
50425056

5043-
for (; i < idx; ++i)
5057+
for (; i < len; ++i)
50445058
{
50455059
size_t re = fac[i];
50465060
tmp = range[re + i];
@@ -5055,6 +5069,41 @@ if (isRandomAccessRange!Range && hasLength!Range)
50555069
}
50565070

50575071
///
5072+
pure @safe unittest
5073+
{
5074+
auto src = [0, 1, 2];
5075+
auto rslt = [0, 2, 1];
5076+
5077+
src = nthPermutation(src, 1);
5078+
assert(src == rslt);
5079+
}
5080+
pure @safe unittest
5081+
{
5082+
auto src = [0, 1, 2, 3];
5083+
auto rslt = [0, 3, 1, 2];
5084+
5085+
src = nthPermutation(src, 4);
5086+
assert(src == rslt);
5087+
}
5088+
pure @safe unittest
5089+
{
5090+
auto src = [0, 1, 2];
5091+
auto rslt = [0, 2, 1];
5092+
5093+
bool worked = nthPermutationImpl(src, 1);
5094+
assert(worked);
5095+
assert(src == rslt);
5096+
}
5097+
pure @safe unittest
5098+
{
5099+
auto src = [0, 1, 2, 3];
5100+
auto rslt = [0, 3, 1, 2];
5101+
5102+
bool worked = nthPermutationImpl(src, 4);
5103+
assert(worked);
5104+
assert(src == rslt);
5105+
}
5106+
50585107
pure @safe unittest
50595108
{
50605109
auto src = [0, 1, 2, 3, 4, 5, 6];
@@ -5076,7 +5125,7 @@ pure @safe unittest
50765125
pure @safe unittest
50775126
{
50785127
auto src = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
5079-
auto rslt = [4, 0, 6, 2, 1, 3, 5, 7, 8, 9, 10];
5128+
auto rslt = [0, 1, 2, 3, 8, 4, 10, 6, 5, 7, 9];
50805129

50815130
src = nthPermutation(src, 2982);
50825131
assert(src == rslt);
@@ -5097,7 +5146,7 @@ pure @safe unittest
50975146
import std.meta : AliasSeq;
50985147

50995148
auto src = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
5100-
auto rsl = [4, 0, 6, 2, 1, 3, 5, 7, 8, 9, 10];
5149+
auto rsl = [0, 1, 2, 3, 8, 4, 10, 6, 5, 7, 9];
51015150

51025151
foreach (T; AliasSeq!(
51035152
DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random, int[]),

0 commit comments

Comments
 (0)