Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- object permutations {
- def withReplacements(chars: String, n: Int) {
- def internal(path: String, acc: List[String]): List[String] = {
- if (path.length == n) path :: acc else
- chars.toList.flatMap {c => internal(path + c, acc)}
- }
- val res = internal("", Nil)
- println("there are " + res.length + " " + n + "-permutations with replacement for " + chars + " = " + res)
- } //> withReplacements: (chars: String, n: Int)Unit
- def indent[A](path: List[A]) = path map (_ => " ")
- //> indent: [A](path: List[A])List[String]
- def noReplacements(chars: String, n: Int/* = chars.length*/) {
- //val set = chars.groupBy(c => c).map {case (c, list) => (c -> list.length)}.toList
- import scala.collection.immutable.Queue
- type Set = Queue[Char]
- type Result = Queue[String]
- // The idea is that recursions will scan the set with one element excluded.
- // Queue was chosen to implement the set to enable excluded element to bubble through it.
- def internal(set: Set, path: String, acc: Result): Result = {
- if (path.length == n) acc.enqueue(path)
- else
- set.foldLeft(acc, set.dequeue){case ((acc, (consumed_el, q)), e) =>
- //{println(path + ": consumed " + consumed_el + ", e=" + e)}
- (internal(q, consumed_el + path, acc), q.enqueue(consumed_el).dequeue)
- }. _1
- }
- val set = Queue[Char](chars.toList: _*)
- val res = internal(set, "", Queue.empty)
- println("there are " + res.length + " " + n + "-permutations without replacement for " + set + " = " + res)
- } //> noReplacements: (chars: String, n: Int)Unit
- withReplacements("abc", 2) //> there are 9 2-permutations with replacement for abc = List(aa, ab, ac, ba,
- //| bb, bc, ca, cb, cc)
- noReplacements("abc", 2) //> there are 6 2-permutations without replacement for Queue(a, b, c) = Queue(b
- //| a, ca, cb, ab, ac, bc)
- def permute(xs:List[Int]):List[List[Int]] = xs match {
- case Nil => List(List())
- case head::tail => {
- val tps = (0 until xs.length).map(xs.splitAt(_)).toList.filter(tp => !tp._1.contains(tp._2.head))
- tps.map(tp => permute(tp._1:::tp._2.tail).map(tp._2.head :: _)).flatten
- }
- } //> permute: (xs: List[Int])List[List[Int]]
- permute(List(1,2,3)) //> res0: List[List[Int]] = List(List(1, 2, 3), List(1, 3, 2), List(2, 1, 3), L
- //| ist(2, 3, 1), List(3, 1, 2), List(3, 2, 1))
- withReplacements("abc", 3) //> there are 27 3-permutations with replacement for abc = List(aaa, aab, aac,
- //| aba, abb, abc, aca, acb, acc, baa, bab, bac, bba, bbb, bbc, bca, bcb, bcc,
- //| caa, cab, cac, cba, cbb, cbc, cca, ccb, ccc)
- withReplacements("abc", 4) //> there are 81 4-permutations with replacement for abc = List(aaaa, aaab, aaa
- //| c, aaba, aabb, aabc, aaca, aacb, aacc, abaa, abab, abac, abba, abbb, abbc,
- //| abca, abcb, abcc, acaa, acab, acac, acba, acbb, acbc, acca, accb, accc, baa
- //| a, baab, baac, baba, babb, babc, baca, bacb, bacc, bbaa, bbab, bbac, bbba,
- //| bbbb, bbbc, bbca, bbcb, bbcc, bcaa, bcab, bcac, bcba, bcbb, bcbc, bcca, bcc
- //| b, bccc, caaa, caab, caac, caba, cabb, cabc, caca, cacb, cacc, cbaa, cbab,
- //| cbac, cbba, cbbb, cbbc, cbca, cbcb, cbcc, ccaa, ccab, ccac, ccba, ccbb, ccb
- //| c, ccca, cccb, cccc)
- //noReplacements("abc", 4)
- (1 to 3) foreach (u => noReplacements("aab", u))//> there are 3 1-permutations without replacement for Queue(a, a, b) = Queue(a
- //| , a, b)
- //| there are 6 2-permutations without replacement for Queue(a, a, b) = Queue(a
- //| a, ba, ba, aa, ab, ab)
- //| there are 6 3-permutations without replacement for Queue(a, a, b) = Queue(b
- //| aa, aba, aba, baa, aab, aab)
- // With permutation implies that we have infinite supply of denominations rather than concrete coins. It is therefore
- // necessary to call it with limiting length to combinations. Otherwise, generation never ends as you can always
- // produce sequences of longer lengths.
- // With permutaions implies that you have only one coin of every kind. The maximum length you can get is equal to the coin/kind number.
- // The famous formula says perms(items, places) = items!/(items-places)! Suppose that there are more places than items -- you will get
- // infinite amount of permutations, http://mathoverflow.net/questions/10124/the-factorial-of-1-2-3/137634#137634!
- // You have seen that noReplacements("aab", n) produces several combinations twice because different entries of a are
- // considered as different elements. In fact we have multisets here https://en.wikipedia.org/wiki/Permutation#k-permutations_of_n
- // and need to collapse the identical expressions. Using the latter algoringm, we reduce coin availalbility, every time it is picked
- // and dequeue it completely only after availability drops to 0.
- noReplacements("abc", 3) //> there are 6 3-permutations without replacement for Queue(a, b, c) = Queue(c
- //| ba, bca, acb, cab, bac, abc)
- // Rewrite with replacement a bit to eliminate flat-map merges.
- def norep2(chars: String, n: Int/* = chars.length*/) {
- import scala.collection.immutable.Queue
- type Set = Queue[Char]
- val set = Queue[Char](chars.toList: _*)
- type Result = Queue[String]
- def siblings(set: (Char, Set), offset: Int, path: String, acc: Result): Result = set match {case (bubble, queue) =>
- val children = descend(queue, path + bubble, acc) // bubble was used, it is not available for children that will produce combinations in other positions
- if (offset == 0) children else siblings(queue.enqueue(bubble).dequeue, offset - 1, path, children) // siblings will produce different chars at the same position, fetch next char for them
- }
- def descend(set: Set, path: String, acc: Result): Result = {
- if (path.length == n) acc.enqueue(path) else siblings(set.dequeue, set.size-1, path, acc)
- }
- val res = descend(set, "", Queue.empty)
- println("there are " + res.length + " " + n + "-permutations without replacement for " + set + " = " + res)
- } //> norep2: (chars: String, n: Int)Unit
- assert(norep2("abc", 2) == noReplacements("abc", 2))
- //> there are 6 2-permutations without replacement for Queue(a, b, c) = Queue(a
- //| b, ac, bc, ba, ca, cb)
- //| there are 6 2-permutations without replacement for Queue(a, b, c) = Queue(b
- //| a, ca, cb, ab, ac, bc)
- assert(norep2("abc", 3) == noReplacements("abc", 3))
- //> there are 6 3-permutations without replacement for Queue(a, b, c) = Queue(a
- //| bc, acb, bca, bac, cab, cba)
- //| there are 6 3-permutations without replacement for Queue(a, b, c) = Queue(c
- //| ba, bca, acb, cab, bac, abc)
- def multisets(chars: String, n: Int/* = chars.length*/) {
- import scala.collection.immutable.Queue
- type Set = Queue[Bubble]
- type Bubble = (Char, Int)
- type Result = Queue[String]
- def siblings(set: (Bubble, Set), offset: Int, path: String, acc: Result): Result = set match {case ((char, avail), queue) =>
- val children = descend(if (avail - 1 == 0) queue else queue.enqueue(char -> {avail-1}), path + char, acc) // childern can reuse the symbol while if it is available
- if (offset == 0) children else siblings(queue.enqueue((char, avail)).dequeue, offset - 1, path, children)
- }
- def descend(set: Set, path: String, acc: Result): Result = {
- if (path.length == n) acc.enqueue(path) else siblings(set.dequeue, set.size-1, path, acc)
- }
- val set = Queue[Bubble]((chars.toList groupBy (c => c) map {case (k, v) => (k, v.length)}).toList: _*)
- val res = descend(set, "", Queue.empty)
- println("there are " + res.length + " multiset " + n + "-permutations for " + set + " = " + res)
- } //> multisets: (chars: String, n: Int)Unit
- assert(multisets("abc", 2) == norep2("abc", 2)) //> there are 6 multiset 2-permutations for Queue((b,1), (a,1), (c,1)) = Queue(
- //| ba, bc, ac, ab, cb, ca)
- //| there are 6 2-permutations without replacement for Queue(a, b, c) = Queue(a
- //| b, ac, bc, ba, ca, cb)
- assert(multisets("abc", 3) == norep2("abc", 3)) //> there are 6 multiset 3-permutations for Queue((b,1), (a,1), (c,1)) = Queue(
- //| bac, bca, acb, abc, cba, cab)
- //| there are 6 3-permutations without replacement for Queue(a, b, c) = Queue(a
- //| bc, acb, bca, bac, cab, cba)
- multisets("aaab", 2) //> there are 3 multiset 2-permutations for Queue((b,1), (a,3)) = Queue(ba, ab,
- //| aa)
- multisets("aab", 2) //> there are 3 multiset 2-permutations for Queue((b,1), (a,2)) = Queue(ba, ab,
- //| aa)
- multisets("aab", 3) //> there are 3 multiset 3-permutations for Queue((b,1), (a,2)) = Queue(baa, ab
- //| a, aab)
- norep2("aab", 3) //> there are 6 3-permutations without replacement for Queue(a, a, b) = Queue(a
- //| ab, aba, aba, aab, baa, baa)
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement