Created
August 31, 2011 13:06
-
-
Save seratch/1183495 to your computer and use it in GitHub Desktop.
S-99 P21-P28 My Work
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// *** S-99: Ninety-Nine Scala Problems *** | |
// http://aperiodic.net/phil/scala/s-99/ | |
// | |
// wget http://www.scala-tools.org/repo-releases/org/scalatest/scalatest_2.9.0-1/1.6.1/scalatest_2.9.0-1-1.6.1.jar | |
// scala -cp scal.test-*.jar s99-21-28.scala | |
import org.scalatest.matchers.ShouldMatchers._ | |
class NotImplementedYet extends RuntimeException | |
object P10 { | |
def pack[T](list: List[T]): List[List[T]] = { | |
if (list.isEmpty) List(List()) | |
else { | |
val (packed, next) = list span { | |
_ == list.head | |
} | |
if (next == Nil) List(packed) | |
else packed :: pack(next) | |
} | |
} | |
def encode[A](ls: List[A]): List[(Int, A)] = pack(ls) map { | |
e => (e.length, e.head) | |
} | |
} | |
object P20 { | |
def removeAt[T](n: Int, list: List[T]): (List[T], T) = { | |
list splitAt (n) match { | |
case (leftN, t) => (leftN ::: t.tail, t.head) | |
case _ => throw new IllegalArgumentException | |
} | |
} | |
} | |
// P21: Insert an element at a given position into a list. | |
object P21 { | |
def insertAt[T](element: T, n: Int, list: List[T]): List[T] = { | |
list.splitAt(n) match { | |
//case (pre,post) => pre ::: List(element) ::: post | |
case (pre,post) => pre ::: element :: post | |
case _ => throw new IllegalArgumentException | |
} | |
} | |
def test { | |
{ | |
val element = 'new | |
val n = 0 | |
val list = List('a, 'b, 'c, 'd) | |
val expected = List('new, 'a, 'b, 'c, 'd) | |
insertAt(element, n, list) should equal(expected) | |
} | |
{ | |
val element = 'new | |
val n = 1 | |
val list = List('a, 'b, 'c, 'd) | |
val expected = List('a, 'new, 'b, 'c, 'd) | |
insertAt(element, n, list) should equal(expected) | |
} | |
{ | |
val element = 'new | |
val n = 2 | |
val list = List('a, 'b, 'c, 'd) | |
val expected = List('a, 'b, 'new, 'c, 'd) | |
insertAt(element, n, list) should equal(expected) | |
} | |
} | |
} | |
// P22: Create a list containing all integers within a given range. | |
object P22 { | |
def range(from: Int, to: Int): List[Int] = { | |
// Range(from, to+1).toList | |
// from to to toList | |
def recursive(to: Int, result: List[Int]): List[Int] = { | |
if (to < from) result | |
else recursive(to-1, to :: result) | |
} | |
//recursive(to, Nil) | |
def unfoldr(start: Int)(func: Int => Option[(Int,Int)]): List[Int] = { | |
func(start) match { | |
case None => Nil | |
case Some((i, j)) => i :: unfoldr(j)(func) | |
} | |
} | |
unfoldr(from) { i => | |
if (i > to) None | |
else Some((i, i+1)) | |
} | |
} | |
def test { | |
{ | |
val from = 4 | |
val to = 9 | |
val expected = List(4, 5, 6, 7, 8, 9) | |
range(from, to) should equal(expected) | |
} | |
{ | |
val from = 0 | |
val to = 3 | |
val expected = List(0, 1, 2, 3) | |
range(from, to) should equal(expected) | |
} | |
} | |
} | |
// P23: Extract a given number of randomly selected elements from a list. | |
object P23 { | |
def randomSelect[T](length: Int, list: List[T]): List[T] = { | |
util.Random.shuffle(list).take(length) | |
} | |
def test { | |
{ | |
val length = 3 | |
val list = List('a, 'b, 'c, 'd, 'f, 'g, 'h) | |
val result1 = randomSelect(length, list) | |
result1.size should equal(length) | |
val result2 = randomSelect(length, list) | |
result2.size should equal(length) | |
(result1 zip result2 zip list filter { | |
case ((a, b), c) => a == b && b == c && c == a | |
}).size should be < length | |
} | |
} | |
} | |
// P24: Lotto: Draw N different random numbers from the set 1..M. | |
object P24 { | |
def lotto(length: Int, max: Int): List[Int] = { | |
// util.Random.shuffle(Range(0,max).toList).take(length) | |
P23.randomSelect(length, Range(0,max).toList) | |
} | |
def test { | |
{ | |
val length = 6 | |
val max = 49 | |
val expected = List(23, 1, 17, 33, 21, 37) | |
val result = lotto(length, max) | |
result foreach { | |
case each => each should be <= max | |
} | |
result.size should equal(6) | |
} | |
} | |
} | |
// P25: Generate a random permutation of the elements of a list. | |
// Hint: Use the solution of problem P23. | |
object P25 { | |
def randomPermute[T](list: List[T]): List[T] = { | |
// util.Random.shuffle(list) | |
byFisherYatesShuffle(list) | |
} | |
private def byFisherYatesShuffle[T](list: List[T]): List[T] = { | |
val r = new util.Random | |
val arr = list.toBuffer | |
for ( i <- arr.length-1 to 1 by -1) { | |
val j = r.nextInt(i+1) | |
val t = arr(i) | |
arr.update(i, arr(j)) | |
arr.update(j, t) | |
} | |
arr.toList | |
} | |
def test { | |
{ | |
val list = List('a, 'b, 'c, 'd, 'e, 'f) | |
val result1 = randomPermute(list) | |
result1.size should equal(list.length) | |
val result2 = randomPermute(list) | |
result2.size should equal(list.length) | |
(result1 zip result2 zip list filter { | |
case ((a, b), c) => { | |
a == b && b == c && c == a | |
} | |
}).size should be < list.length | |
} | |
} | |
} | |
// P26: Generate the combinations of K distinct objects chosen from the N elements of a list. | |
// In how many ways can a committee of 3 be chosen from a group of 12 people? | |
// We all know that there are C(12,3) = 220 possibilities (C(N,K) denotes the well-known binomial coefficient). | |
// For pure mathematicians, this result may be great. But we want to really generate all the possibilities. | |
object P26 { | |
def combinations[T](n: Int, list: List[T]): List[List[T]] = { | |
if (n == 0) List(Nil) | |
else { | |
def execute(ls: List[T]): List[List[T]] = { | |
val head = ls.head | |
val tailCombis = combinations(n-1, ls.tail) | |
tailCombis map { tailCombi: List[T] => { head :: tailCombi } } | |
} | |
val f = execute _ | |
sublists(list) flatMap f | |
} | |
} | |
def sublists[A](list: List[A]) : List[List[A]] = { | |
list match { | |
case Nil => Nil | |
case _ :: tail => list :: sublists(tail) | |
} | |
} | |
def test { | |
{ | |
val n = 2 | |
val list = List('a, 'b, 'c, 'd, 'e, 'f) | |
val result = combinations(n, list) | |
val expected = List( | |
List('a, 'b), List('a, 'c), List('a, 'd), List('a, 'e), | |
List('a, 'f), List('b, 'c), List('b, 'd), List('b, 'e), | |
List('b, 'f), List('c, 'd), List('c, 'e), List('c, 'f), | |
List('d, 'e), List('d, 'f), List('e, 'f) | |
) | |
result should equal(expected) | |
} | |
{ | |
val n = 3 | |
val list = List('a, 'b, 'c, 'd, 'e, 'f) | |
val expected: List[List[Symbol]] = | |
List( | |
List('a, 'b, 'c), List('a, 'b, 'd), | |
List('a, 'b, 'e), List('a, 'b, 'f), | |
List('a, 'c, 'd), List('a, 'c, 'e), | |
List('a, 'c, 'f), List('a, 'd, 'e), | |
List('a, 'd, 'f), List('a, 'e, 'f), | |
List('b, 'c, 'd), List('b, 'c, 'e), | |
List('b, 'c, 'f), List('b, 'd, 'e), | |
List('b, 'd, 'f), List('b, 'e, 'f), | |
List('c, 'd, 'e), List('c, 'd, 'f), | |
List('c, 'e, 'f), List('d, 'e, 'f) | |
) | |
val result = combinations(n, list) | |
result.size should equal(20) | |
result should equal(expected) | |
} | |
} | |
} | |
// P27: Group the elements of a set into disjoint subsets. | |
object P27 { | |
// a) In how many ways can a group of 9 people work in 3 disjoint subgroups of 2, 3 and 4 persons? | |
// Write a function that generates all the possibilities. | |
def group3(list: List[String]): List[List[List[String]]] = { | |
/* | |
P26.combinations(2, list) flatMap { | |
case two => { | |
val withoutTwo = list filterNot { e => two.contains(e) } | |
P26.combinations(3, withoutTwo) map { | |
case three => { | |
val four = withoutTwo filterNot { e => three.contains(e) } | |
List(two, three, four) | |
} | |
} | |
} | |
} | |
*/ | |
for { | |
a <- P26.combinations(2, list) | |
notInA = list filterNot { a.contains _ } | |
b <- P26.combinations(3, notInA) | |
} yield List(a, b, notInA filterNot { b contains _ }) | |
} | |
// b) Generalize the above predicate in a way that we can specify a list of group sizes | |
// and the predicate will return a list of groups. | |
def group(nums: List[Int], members: List[String]): List[List[List[String]]] = { | |
nums match { | |
case Nil => List(Nil) | |
case n :: numtail => P26.combinations(n, members) flatMap { | |
case combi => { | |
val notInCombi = members filterNot { combi contains _ } | |
group(numtail, notInCombi) map { grouped => combi :: grouped } | |
} | |
} | |
} | |
} | |
def test { | |
{ | |
val list = List("Aldo", "Beat", "Carla", "David", "Evi", "Flip", "Gary", "Hugo", "Ida") | |
val result = group3(list) | |
result.size should equal(1260) | |
} | |
{ | |
val nums = List(2, 2, 5) | |
val list = List("Aldo", "Beat", "Carla", "David", "Evi", "Flip", "Gary", "Hugo", "Ida") | |
val result = group(nums, list) | |
result.size should equal(756) | |
} | |
} | |
} | |
// P28: Sorting a list of lists according to length of sublists. | |
object P28 { | |
// a) We suppose that a list contains elements that are lists themselves. | |
// The objective is to sort the elements of the list according to their length. | |
// E.g. short lists first, longer lists later, or vice versa. | |
def lsort[T](listOfLists: List[List[T]]): List[List[T]] = { | |
listOfLists sortWith { (a,b) => a.length < b.length } | |
} | |
// b) Again, we suppose that a list contains elements that are lists themselves. | |
// But this time the objective is to sort the elements according to their length frequency; | |
// i.e. in the default, sorting is done ascendingly, lists with rare lengths are placed, | |
// others with a more frequent length come later. | |
def lsortFreq[T](list: List[List[T]]): List[List[T]] = { | |
// val freqs = Map(P10.encode(list map { _.length } sort { _ < _ }) map { _.swap }:_*) | |
val lengthList = list map { _.length } sortWith { (a,b) => a < b } // List(1, 2, 2, 2, 3, 3, 4) | |
val encoded = P10.encode(lengthList)) // List((1,1), (3,2), (2,3), (1,4)) | |
val swapedEncoded = encoded map { e => e.swap } // List((1,1), (2,3), (3,2), (4,1)) | |
val freqs = Map(swapedEncoded: _*) // frequencies of length | |
list sortWith { (a,b) => freqs(a.length) < freqs(b.length) } | |
} | |
def test { | |
{ | |
val listOfLists = List(List('a, 'b, 'c), List('d, 'e), List('f, 'g, 'h), List('d, 'e), List('i, 'j, 'k, 'l), List('m, 'n), List('o)) | |
val expected = List(List('o), List('d, 'e), List('d, 'e), List('m, 'n), List('a, 'b, 'c), List('f, 'g, 'h), List('i, 'j, 'k, 'l)) | |
lsort(listOfLists) should equal(expected) | |
} | |
{ | |
val listOfLists = List(List('a, 'b, 'c), List('d, 'e), List('f, 'g, 'h), List('d, 'e), List('i, 'j, 'k, 'l), List('m, 'n), List('o)) | |
val expected = List(List('i, 'j, 'k, 'l), List('o), List('a, 'b, 'c), List('f, 'g, 'h), List('d, 'e), List('d, 'e), List('m, 'n)) | |
lsortFreq(listOfLists) should equal(expected) | |
} | |
} | |
} | |
P21.test | |
P22.test | |
P23.test | |
P24.test | |
P25.test | |
P26.test | |
P27.test | |
P28.test | |
// vim: set ts=4 sw=4 et: |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment