Best shuffle: Difference between revisions

Content added Content deleted
(Improved D version)
(→‎{{header|AWK}}: Add translation from Icon; this is simpler than the translation from Perl 6.)
Line 6: Line 6:


=={{header|AWK}}==
=={{header|AWK}}==
{{trans|Perl 6}}
=== {{trans|Icon}} ===
The Icon and Unicon program uses a simple algorithm of swapping. This is relatively easy to translate to Awk.


<lang awk>{
Awk is a poor choice for this task, because Awk provides no array functions, except for split(). This Awk program uses its own code
scram = best_shuffle($0)
print $0 " -> " scram " (" unchanged($0, scram) ")"
}

function best_shuffle(s, c, i, j, len, r, t) {
len = split(s, t, "")

# Swap elements of t[] to get a best shuffle.
for (i = 1; i <= len; i++) {
for (j = 1; j <= len; j++) {
# Swap t[i] and t[j] if they will not match
# the original characters from s.
if (i != j &&
t[i] != substr(s, j, 1) &&
substr(s, i, 1) != t[j]) {
c = t[i]
t[i] = t[j]
t[j] = c
break
}
}
}

# Join t[] into one string.
r = ""
for (i = 1; i <= len; i++)
r = r t[i]
return r
}

function unchanged(s1, s2, count, len) {
count = 0
len = length(s1)
for (i = 1; i <= len; i++) {
if (substr(s1, i, 1) == substr(s2, i, 1))
count++
}
return count
}</lang>

This program has the same output as the Icon and Unicon program.

=== {{trans|Perl 6}} ===
The Perl 6 program (and the equivalent Ruby program) use several built-in array functions. Awk provides no array functions, except for split(). This Awk program, a translation from Perl 6, uses its own code


* to sort an array,
* to sort an array,
Line 16: Line 61:
* to join the elements of an array into a string.
* to join the elements of an array into a string.


The equivalent programs for [[#Perl 6|Perl 6]] and for [[#Ruby|Ruby]] use several built-in array functions. But if those array functions seem strange to you, and if you can understand this bunch of for loops, then you might prefer this Awk program.
If those built-in array functions seem strange to you, and if you can understand these for loops, then you might prefer this Awk program. This algorithm counts the letters in the string, sorts the positions, and fills the positions in order.

This algorithm calculates an order of positions, then fills a new string in this order, by moving each letter from the original string. It will never replace an old letter with an identical letter, unless the remainder of the original string has only this letter. The next position to fill is always the position of the old letter with the most occurrences among the remaining old letters. This special order can always change every old letter, unless some old letter occurs in more than half of the original string.


<lang awk># out["string"] = best shuffle of string _s_
<lang awk># out["string"] = best shuffle of string _s_
Line 66: Line 109:
# Now fill in _new_ with _letters_ according to each position
# Now fill in _new_ with _letters_ according to each position
# in pos[slen], ..., pos[1], but skip ahead in _letters_
# in pos[slen], ..., pos[1], but skip ahead in _letters_
# if we can avoid matching characteers that way.
# if we can avoid matching characters that way.
rlen = split(s, letters, "")
rlen = split(s, letters, "")
for (i = slen; i >= 1; i--) {
for (i = slen; i >= 1; i--) {
Line 110: Line 153:
a, a, (1)</lang>
a, a, (1)</lang>


The output might change if the <tt>for (c in set)</tt> loop iterates the array in a different order. (Awk specifies not an order of iteration.)
The output might change if the <tt>for (c in set)</tt> loop iterates the array in a different order.


=={{header|C}}==
=={{header|C}}==