I'm trying to code up something very simple in D, but I'm having a few problems with one of the standard library template functions (specifically, nextPermutation
from std.algorithm
).
The crux of what I'm trying to do is to create all permutations of pandigital numbers (that is, numbers including all the values 1 to 9 exactly once).
To do this, I've done the following:
import std.algorithm;
import std.conv;
int[] pandigitals()
{
char[] initial = "123456789".dup;
auto pan = [to!int(initial)];
while(nextPermutation!(initial)) {
pan ~= to!int(initial);
}
return pan;
}
This gives me the error:
Error: cannot resolve type for nextPermutation!(initial)
I've also tried to explicitly set the types:
while(nextPermutation!("a<b", char[])(initial))
However, this gives an error saying it cannot match the template:
Error: template instance std.algorithm.nextPermutation!("a < b", char[]) does not match template declaration nextPermutation(alias less = "a < b", BidirectionalRange)(ref BidirectionalRange range) if (isBidirectionalRange!BidirectionalRange && hasSwappableElements!BidirectionalRange)
What is the correct form of the call meant to be?
Well, your first problem is that you're passing initial
as a template argument instead of a function argument. The !()
is for template arguments. so, instead of
while(nextPermutation!(initial))
you need to do
while(nextPermutation(initial)) {
Now, that will still give you an error.
q.d(10): Error: template std.algorithm.nextPermutation cannot deduce function from argument types !()(char[]), candidates are:
/usr/include/D/phobos/std/algorithm.d(12351): std.algorithm.nextPermutation(alias less = "a<b", BidirectionalRange)(ref BidirectionalRange range) if (isBidirectionalRange!BidirectionalRange && hasSwappableElements!BidirectionalRange)
And that's because hasSwappableElements!(char[])
is false
, and per nextPermutations
' template constraint it needs to be true
for a type to work with nextPermutations
.
It's false
because all strings are treated as ranges of dchar
rather than their actual element type. This is because in UTF-8 (char
) and UTF-16 (wchar
), there are multiple code units per code point, so operating on individual code units could break up a code point, whereas in UTF-32 (dchar
), there's always one code unit per code point. Essentially, if arrays of char
or wchar
were treated as ranges of char
or wchar
, you'd run a high risk of breaking up characters so that you'd end up with pieces of characters rather than whole characters. So, in general in D, if you want to operate on an individual character, you should use dchar
, not char
or wchar
. If you're not very familiar with Unicode, I'd suggest reading this article by Joel Spoelsky on the subject.
However, regardless of why hasSwappableElements!(char[])
is false
, it is false
, so you're going to need to use a different type. The simplest thing would probably be to just swap your algorithm over to using dchar[]
instead.
int[] pandigitals()
{
dchar[] initial = "123456789"d.dup;
auto pan = [to!int(initial)];
while(nextPermutation(initial)) {
pan ~= to!int(initial);
}
return pan;
}