Skip to content

Commit 6fc2129

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

1 file changed

Lines changed: 50 additions & 4 deletions

File tree

std/algorithm/sorting.d

Lines changed: 50 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,7 @@ bool nthPermutationImpl(Range)
50255025
(auto ref Range range, ulong perm)
50265026
if (isRandomAccessRange!Range && hasLength!Range)
50275027
{
5028+
50285029
import std.range.primitives : ElementType;
50295030
import std.numeric : decimalToFactorial;
50305031

@@ -5037,10 +5038,20 @@ if (isRandomAccessRange!Range && hasLength!Range)
50375038
return false;
50385039
}
50395040

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

5043-
for (; i < idx; ++i)
5054+
for (; i < len; ++i)
50445055
{
50455056
size_t re = fac[i];
50465057
tmp = range[re + i];
@@ -5055,6 +5066,41 @@ if (isRandomAccessRange!Range && hasLength!Range)
50555066
}
50565067

50575068
///
5069+
pure @safe unittest
5070+
{
5071+
auto src = [0, 1, 2];
5072+
auto rslt = [0, 2, 1];
5073+
5074+
src = nthPermutation(src, 1);
5075+
assert(src == rslt);
5076+
}
5077+
pure @safe unittest
5078+
{
5079+
auto src = [0, 1, 2, 3];
5080+
auto rslt = [0, 3, 1, 2];
5081+
5082+
src = nthPermutation(src, 4);
5083+
assert(src == rslt);
5084+
}
5085+
pure @safe unittest
5086+
{
5087+
auto src = [0, 1, 2];
5088+
auto rslt = [0, 2, 1];
5089+
5090+
bool worked = nthPermutationImpl(src, 1);
5091+
assert(worked);
5092+
assert(src == rslt);
5093+
}
5094+
pure @safe unittest
5095+
{
5096+
auto src = [0, 1, 2, 3];
5097+
auto rslt = [0, 3, 1, 2];
5098+
5099+
bool worked = nthPermutationImpl(src, 4);
5100+
assert(worked);
5101+
assert(src == rslt);
5102+
}
5103+
50585104
pure @safe unittest
50595105
{
50605106
auto src = [0, 1, 2, 3, 4, 5, 6];
@@ -5076,7 +5122,7 @@ pure @safe unittest
50765122
pure @safe unittest
50775123
{
50785124
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];
5125+
auto rslt = [0, 1, 2, 3, 8, 4, 10, 6, 5, 7, 9];
50805126

50815127
src = nthPermutation(src, 2982);
50825128
assert(src == rslt);
@@ -5097,7 +5143,7 @@ pure @safe unittest
50975143
import std.meta : AliasSeq;
50985144

50995145
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];
5146+
auto rsl = [0, 1, 2, 3, 8, 4, 10, 6, 5, 7, 9];
51015147

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

0 commit comments

Comments
 (0)