Combinations with repetitions: Difference between revisions
Content added Content deleted
(→{{header|PHP}}: output) |
(Updated D code) |
||
Line 189: | Line 189: | ||
=={{header|D}}== |
=={{header|D}}== |
||
Using [http://www-graphics.stanford.edu/~seander/bithacks.html#NextBitPermutation lexicographic next bit permutation] to generate combinations with repetitions. |
Using [http://www-graphics.stanford.edu/~seander/bithacks.html#NextBitPermutation lexicographic next bit permutation] to generate combinations with repetitions. |
||
<lang d>import std.stdio, std.range |
<lang d>import std.stdio, std.range; |
||
struct CombRep { |
/*immutable*/ const struct CombRep { |
||
immutable uint nt, nc |
immutable uint nt, nc; |
||
private ulong[] combVal; |
private /*immutable*/ ulong[] combVal; |
||
this(uint numType, uint numChoice) { |
this(in uint numType, in uint numChoice) pure nothrow { |
||
assert(0 < numType && numType + numChoice <= 64, |
assert(0 < numType && numType + numChoice <= 64, |
||
"valid only for nt + nc <= 64 (ulong bit size)") |
"valid only for nt + nc <= 64 (ulong bit size)"); |
||
nt = numType |
nt = numType; |
||
nc = numChoice |
nc = numChoice; |
||
if(nc == 0) |
if (nc == 0) |
||
return; |
|||
auto v = (1UL << (nt - 1)) - 1; |
|||
// init to smallest number that has nt-1 bit set |
// init to smallest number that has nt-1 bit set |
||
// a set bit is metaphored as a _type_ seperator |
// a set bit is metaphored as a _type_ seperator |
||
immutable limit = v << nc |
immutable limit = v << nc; |
||
// limit is the largest nt-1 bit set number that has nc zero-bit |
|||
// |
// limit is the largest nt-1 bit set number that has nc |
||
// zero-bit a zero-bit means a _choice_ between _type_ |
|||
⚫ | |||
// seperators |
|||
while (v <= limit) { |
|||
combVal ~= v; |
|||
if (v == 0) |
|||
break; |
|||
// get next nt-1 bit number |
|||
immutable t = (v | (v - 1)) + 1; |
|||
v = t | ((((t & -t) / (v & -v)) >> 1) - 1); |
|||
} |
} |
||
} |
} |
||
⚫ | |||
uint |
uint length() @property const pure nothrow { |
||
⚫ | |||
} |
|||
uint[] opIndex(in uint idx) const pure nothrow { |
|||
return val2set(combVal[idx]); |
|||
} |
|||
int opApply(int delegate(ref uint[]) dg) { |
int opApply(int delegate(ref uint[]) dg) { |
||
foreach(v;combVal) { |
foreach (v; combVal) { |
||
auto set = val2set(v) |
auto set = val2set(v); |
||
if(dg(set)) |
if (dg(set)) |
||
break |
break; |
||
} |
} |
||
return 1 |
return 1; |
||
} |
} |
||
private uint[] val2set(ulong v) pure { |
private uint[] val2set(in ulong v) const pure nothrow { |
||
// convert bit pattern to selection set |
// convert bit pattern to selection set |
||
uint |
immutable uint bitLimit = nt + nc - 1; |
||
uint |
uint typeIdx = 0; |
||
uint[] set; |
|||
foreach (bitNum; 0 .. bitLimit) |
|||
if (v & (1 << (bitLimit - bitNum - 1))) |
|||
typeIdx++; |
|||
else |
else |
||
set ~= typeIdx |
set ~= typeIdx; |
||
return set |
return set; |
||
} |
} |
||
} |
} |
||
// |
// For finite Random Access Range |
||
auto combRep(R)(R types, uint numChoice) |
auto combRep(R)(R types, in uint numChoice) /*pure nothrow*/ |
||
if (hasLength!R && isRandomAccessRange!R) { |
|||
ElementType!R[][] result |
ElementType!R[][] result; |
||
foreach(s |
foreach (s; CombRep(types.length, numChoice)) { |
||
ElementType!R[] r ; |
|||
ElementType!R[] r; |
|||
foreach (i; s) |
|||
r ~= types[i]; |
|||
⚫ | |||
} |
} |
||
return result |
return result; |
||
} |
} |
||
void main() { |
void main() { |
||
foreach(e;combRep(["iced","jam","plain"],2)) |
foreach (e; combRep(["iced", "jam", "plain"], 2)) |
||
writefln("%5s", e) |
// writefln("%5s", e); |
||
writeln(e); |
|||
writeln("Ways to select 3 from 10 types is ", |
|||
CombRep(10, 3).length); |
|||
}</lang> |
}</lang> |
||
output: |
output: |
||
<pre>[ |
<pre>["iced", "iced"] |
||
[ |
["iced", "jam"] |
||
[ |
["iced", "plain"] |
||
[ |
["jam", "jam"] |
||
[ |
["jam", "plain"] |
||
[plain, plain] |
["plain", "plain"] |
||
Ways to select 3 from 10 types is 220</pre> |
Ways to select 3 from 10 types is 220</pre> |
||