Best shuffle: Difference between revisions
Content added Content deleted
No edit summary |
|||
Line 2,605: | Line 2,605: | ||
up pu 0 |
up pu 0 |
||
a a 1</pre> |
a a 1</pre> |
||
=={{header|Scala}}== |
|||
There are two implementations. One is simple but exponential and very inefficient. The second one is quadratic. Both are pure functional. Given quadratic solution has a bigger constant than the one used in the Python implementation, but doesn't use mutable datastructures. |
|||
<lang scala> |
|||
def coincidients(s1: Seq[Char], s2: Seq[Char]): Int = (s1, s2).zipped.count(p => (p._1 == p._2)) |
|||
def freqMap(s1: List[Char]) = s1.groupBy(_.toChar).mapValues(_.size) |
|||
def estimate(s1: List[Char]): Int = if (s1 == Nil) 0 else List(0, freqMap(s1).maxBy(_._2)._2 - (s1.size / 2)).max |
|||
def bestShuffle(s: String): Pair[String, Int] = { |
|||
if (s == "") return ("", 0) else {} |
|||
val charList = s.toList |
|||
val estim = estimate(charList) |
|||
// purely functional polynomial solution |
|||
def doStep(accu: List[Pair[Int, Int]], sourceFreqMap: Map[Int, Int], targetFreqMap: Map[Int, Int], stepsLeft: Int): List[Pair[Int, Int]] = { |
|||
if (stepsLeft == 0) accu else { |
|||
val srcChoices = sourceFreqMap.groupBy(_._2).minBy(_._1)._2 |
|||
val src = srcChoices.toList.apply(Random.nextInt(srcChoices.size))._1 |
|||
val tgtChoices = targetFreqMap.map(p => if (charList(p._1) != charList(src)) (p._1, p._2) else (p._1, Int.MaxValue / 2)).groupBy(_._2).minBy(_._1)._2 |
|||
val tgt = tgtChoices.toList.apply(Random.nextInt(tgtChoices.size))._1 |
|||
doStep((src, tgt) :: accu, |
|||
sourceFreqMap.filterKeys(_ != src).map(p => if (charList(p._1) != charList(tgt)) (p._1, p._2 - 1) else (p._1, p._2)), |
|||
targetFreqMap.filterKeys(_ != tgt).map(p => if (charList(p._1) != charList(src)) (p._1, p._2 - 1) else (p._1, p._2)), |
|||
stepsLeft - 1) |
|||
} |
|||
} |
|||
val leftFreqMap: Map[Int, Int] = charList.zipWithIndex.map(p => (p._2, p._1)).toMap.mapValues(x => freqMap(charList).mapValues(charList.size - _)(x)) |
|||
val substs = doStep(List(), leftFreqMap, leftFreqMap, charList.size) |
|||
val res = substs.sortBy(_._1).map(p => charList(p._2)) |
|||
(res.mkString, coincidients(charList, res)) |
|||
// exponential solution (inefficient) |
|||
//Random.shuffle(charList).permutations.find(coincidients(charList, _) <= estim) |
|||
} |
|||
</lang> |
|||
The test code: |
|||
<lang scala> |
|||
def main(args: Array[String]): Unit = { |
|||
println(bestShuffle("abracadabra")); |
|||
println(bestShuffle("seesaw")); |
|||
println(bestShuffle("elk")); |
|||
println(bestShuffle("grrrrrr")); |
|||
println(bestShuffle("up")); |
|||
println(bestShuffle("a")); |
|||
BestShuffleSpecification.check |
|||
} |
|||
</lang> |
|||
{{out}} |
|||
<pre> |
|||
(bcabadaraar,0) |
|||
(easews,0) |
|||
(kel,0) |
|||
(rgrrrrr,5) |
|||
(pu,0) |
|||
(a,1) |
|||
</pre> |
|||
The ScalaCheck code |
|||
<lang scala> |
|||
object BestShuffleSpecification extends Properties("BestShuffle") { |
|||
property("size") = forAll { (src: String) => |
|||
val s = Main.bestShuffle(src) |
|||
s._1.size == src.size |
|||
} |
|||
property("freq") = forAll { (src: String) => |
|||
val s = Main.bestShuffle(src) |
|||
Main.freqMap(s._1.toList) == Main.freqMap(src.toList) |
|||
} |
|||
property("estimate") = forAll { (src: String) => |
|||
val s = Main.bestShuffle(src) |
|||
Main.estimate(src.toList) == s._2 |
|||
} |
|||
} |
|||
</lang> |
|||
=={{header|Scheme}}== |
=={{header|Scheme}}== |