Best shuffle: Difference between revisions
Content added Content deleted
(Updates D entries, tags) |
|||
Line 1,051: | Line 1,051: | ||
=={{header|D}}== |
=={{header|D}}== |
||
===Simpler Version=== |
|||
{{works with|D|2}} |
|||
Translation of [[Best_shuffle#Icon_and_Unicon|Icon]] via [[Best_shuffle#AWK|AWK]] |
Translation of [[Best_shuffle#Icon_and_Unicon|Icon]] via [[Best_shuffle#AWK|AWK]] |
||
<lang d>import std.stdio, std.random, std.algorithm, std.conv, std.range, |
<lang d>import std.stdio, std.random, std.algorithm, std.conv, std.range, |
||
std.typecons; |
std.typecons; |
||
auto bestShuffle(in dstring o){ |
auto bestShuffle(in dstring o) { |
||
auto s = o.dup; |
auto s = o.dup; |
||
randomShuffle( |
s.randomShuffle(); |
||
⚫ | |||
foreach (i, ref ci; s) { |
foreach (i, ref ci; s) { |
||
if (ci != o[i]) |
if (ci != o[i]) |
||
continue; |
continue; |
||
foreach (j, ref cj; s) |
foreach (j, ref cj; s) |
||
if (ci != cj && ci != o[j] && cj != o[i]) { |
if (ci != cj && ci != o[j] && cj != o[i]) { |
||
swap(ci, cj); |
swap(ci, cj); |
||
Line 1,070: | Line 1,070: | ||
} |
} |
||
return tuple(s, count!q{ a[0] == a[1] }( |
return tuple(s, zip(s, o).count!q{ a[0] == a[1] }()); |
||
⚫ | |||
} |
|||
⚫ | |||
assert(bestShuffle("abracadabra"d)[1] == 0); |
assert(bestShuffle("abracadabra"d)[1] == 0); |
||
assert(bestShuffle("immediately"d)[1] == 0); |
assert(bestShuffle("immediately"d)[1] == 0); |
||
Line 1,084: | Line 1,082: | ||
} |
} |
||
void main(string[] args) { |
void main(/*in*/ string[] args) { |
||
if (args.length > 1) { |
if (args.length > 1) { |
||
string entry = |
string entry = args[1 .. $].join(" "); |
||
auto res = |
auto res = entry.dtext().bestShuffle(); |
||
writefln("%s : %s (% |
writefln("%s : %s (%d)", entry, res.tupleof); |
||
} |
} |
||
}</lang> |
}</lang> |
||
=== |
===Faster Version=== |
||
<lang d>import std.stdio, std.algorithm, std.range; |
<lang d>import std.stdio, std.algorithm, std.range; |
||
extern(C) pure nothrow void* alloca(in size_t size); |
extern(C) pure nothrow void* alloca(in size_t size); |
||
void bestShuffle(in char[] txt, ref char[] result) pure nothrow { |
|||
// Assume alloca to be pure. |
|||
//extern(C) pure nothrow void* alloca(in size_t size); |
|||
enum size_t NCHAR = cast(size_t)char.max + 1; |
enum size_t NCHAR = cast(size_t)char.max + 1; |
||
enum size_t MAX_VLA_SIZE = 1024; |
enum size_t MAX_VLA_SIZE = 1024; |
||
Line 1,102: | Line 1,102: | ||
if (len == 0) |
if (len == 0) |
||
return; |
return; |
||
// txt and result must have the same length |
// txt and result must have the same length |
||
// allocate only when necessary |
// allocate only when necessary |
||
if (result.length != len) |
if (result.length != len) |
||
result.length = len; |
result.length = len; |
||
// how many of each character? |
// how many of each character? |
||
size_t[NCHAR] counts; |
size_t[NCHAR] counts; |
||
Line 1,117: | Line 1,117: | ||
} |
} |
||
assert(fmax > 0 && fmax <= len); |
assert(fmax > 0 && fmax <= len); |
||
// all character positions, grouped by character |
// all character positions, grouped by character |
||
size_t |
size_t[] ndx1; |
||
⚫ | |||
if ((len * size_t.sizeof) < MAX_VLA_SIZE) |
|||
size_t* ptr1; |
|||
if ((len * size_t.sizeof) < MAX_VLA_SIZE) |
|||
ptr1 = cast(size_t*)alloca(len * size_t.sizeof); |
|||
// If alloca() has failed, or the memory needed is too much |
|||
⚫ | |||
// large, then allocate from the heap. |
|||
ndx1 = (ptr1 == null) ? new size_t[len] : ptr1[0 .. len]; |
|||
} |
|||
⚫ | |||
{ |
|||
⚫ | |||
int pos = 0; |
|||
foreach (size_t ch; 0 .. NCHAR) |
|||
⚫ | |||
foreach (j, char c; txt) |
|||
if (c == ch) { |
|||
⚫ | |||
pos++; |
|||
⚫ | |||
} |
|||
// regroup them for cycles |
// regroup them for cycles |
||
size_t |
size_t[] ndx2; |
||
{ |
|||
if ((len * size_t.sizeof) < MAX_VLA_SIZE) |
|||
size_t* ptr2; |
|||
if ((len * size_t.sizeof) < MAX_VLA_SIZE) |
|||
ptr2 = cast(size_t*)alloca(len * size_t.sizeof); |
|||
ndx2[ |
ndx2 = (ptr2 == null) ? new size_t[len] : ptr2[0 .. len]; |
||
} |
|||
{ |
|||
size_t n, m; |
|||
foreach (size_t i; 0 .. len) { |
|||
ndx2[i] = ndx1[n]; |
|||
⚫ | |||
if (n >= len) { |
|||
m++; |
|||
n = m; |
|||
} |
|||
} |
} |
||
} |
} |
||
// how long can our cyclic groups be? |
// how long can our cyclic groups be? |
||
immutable size_t grp = 1 + (len - 1) / fmax; |
immutable size_t grp = 1 + (len - 1) / fmax; |
||
// how many of them are full length? |
// how many of them are full length? |
||
immutable size_t lng = 1 + (len - 1) % fmax; |
immutable size_t lng = 1 + (len - 1) % fmax; |
||
// rotate each group |
// rotate each group |
||
{ |
|||
⚫ | |||
size_t j; |
|||
foreach (size_t i; 0 .. fmax) { |
|||
immutable size_t first = ndx2[j]; |
|||
immutable size_t glen = grp - (i < lng ? 0 : 1); |
|||
foreach (size_t k; 1 .. glen) |
|||
j += |
ndx1[j + k - 1] = ndx2[j + k]; |
||
ndx1[j + glen - 1] = first; |
|||
j += glen; |
|||
} |
|||
} |
} |
||
// result is original permuted according to our cyclic groups |
// result is original permuted according to our cyclic groups |
||
foreach (size_t i; 0 .. len) |
foreach (size_t i; 0 .. len) |
||
result[ndx2[i]] = txt[ndx1[i]]; |
result[ndx2[i]] = txt[ndx1[i]]; |
||
} |
} |
||
void main() { |
void main() { |
||
auto data = ["abracadabra", "seesaw", "elk", "grrrrrr", |
auto data = ["abracadabra", "seesaw", "elk", "grrrrrr", |
||
"up", "a", "aabbbbaa", "", "xxxxx"]; |
"up", "a", "aabbbbaa", "", "xxxxx"]; |
||
foreach (txt; data) { |
foreach (txt; data) { |
||
auto |
auto result = txt.dup; |
||
bestShuffle(txt, |
bestShuffle(txt, result); |
||
immutable |
immutable nEqual = zip(txt, result).count!q{a[0] == a[1]}(); |
||
writefln("%s, %s, (%d)", txt, |
writefln("%s, %s, (%d)", txt, result, nEqual); |
||
} |
} |
||
}</lang> |
}</lang> |
||
{{out}} |
|||
Output: |
|||
<pre>abracadabra, brabacadaar, (0) |
<pre>abracadabra, brabacadaar, (0) |
||
seesaw, wssaee, (0) |
seesaw, wssaee, (0) |