Elegant way to systematically
Lets write a polymorphic frequency finder.
def freq[A](xs: Iterable[A]): HashMap[A, Int] = {
val freqMap = new HashMap[A, Int]
for (x <- xs) {
freqMap(x) = 1 + freqMap.getOrElse(x, 0)
}
freqMap
}
Iterable[A] describes objects that can be iterated over...
Can run it on Strings
scala> freq("caterillar")
res: scala.collection.mutable.HashMap[Char,Int]
= Map(c -> 1, a -> 2, e -> 1, i -> 1, r -> 2, t -> 1, l -> 2)
or List
scala> freq(List(1,2,1,13,1,2,1,3,31,12,1))
res: scala.collection.mutable.HashMap[Int,Int]
= Map(12 -> 1, 3 -> 1, 13 -> 1, 1 -> 5, 2 -> 2, 31 -> 1)
or ...
Elegant way to systematically
Generate Combinations
Search Combinations
Generate & Search Combinations
Nested loops are like cartesian products
scala> for ( i <- List(1, 2)
; j <- List("a", "b"))
yield (i, j)
res0: List[(Int, String)] = List((1,a), (1,b), (2,a), (2,b))
Result is empty if either the first sequence is empty
scala> for ( i <- List(1,2)
; j <- List())
yield (i, j)
res1: List[(Int, String)] = List()
or the second sequence is empty
scala> for ( i <- List()
; j <- List("a", "b"))
yield (i, j)
res2: List[(Nothing, String)] = List()
def bitStrs(n: Int) : List[String] =
if (n <= 0) { List() } else {
for (c <- List("0", "1");
s <- bitStrs(n-1))
yield(c + s)
}
How can we fix this function so that:
bitStrs(1) ==> List("0","1")
bitStrs(2) ==> List("00","01","10","11")
bitStrs(3) ==> List("000","001","010","011","100","101","110","111")
etc. ?
bitStrs(0))""0def bitStrings(n: Int) : List[String] =
if (n <= 0) { List("") } else {
for (c <- List("0", "1");
s <- bitStrings(n-1))
yield(c + s)
}
substrings is almost identical to transformCapitalize
subStringsReplace each character "c" by either "c" or ""
transformCapitalizeReplace each character "c" by either "c" or "C"
transformDigitsElegant way to systematically
Generate Combinations
Search Combinations
Generate & Search Combinations
case class Name(x1: T1, x2: T2, ..., xn: TN)
Creates a class Name with
x1 of type T1 ... xn of type TnNovelHere is a case class (just fancy records for now...)
case class Novel(title: String, author: String)
You can create instances thus (no need for new)
scala> val n1 = Novel ("A Feast For Crows", "George R. R. Martin")
n1: Novel = Novel(A Feast For Crows,George R. R. Martin)
and access fields like so
scala> n1.author
n1: String = George R. R. Martin
NovelHere is another case class (just fancy records for now...)
case class Album(title: String, artist: String)
You can create instances thus (no need for new)
scala> val a = Album("We are glitter", "Goldfrapp")
a: Album = Album(We are glitter,Goldfrapp)
Suppose we have a "database" of novels
val novels =
List( Novel ( "Skinny Legs and All"
, "Tom Robbins")
, Novel ( "Breakfast of Champions"
, "Kurt Vonnegut")
, Novel ( "An Object of Beauty"
, "Steve Martin")
, Novel ( "Sophie's Choice"
, "William Styron")
, Novel ( "The Other"
, "Tom Tryon")
)
... and a "database" of albums
val albums =
List( Album ( "Rare Bird Alert"
, "Steve Martin")
, Album ( "Paper Airplane"
, "Alison Krauss and Union Station")
, Album ( "Earl Scruggs and Friends"
, "Earl Scruggs")
)
... and a "database" of movies
val movies =
List( Movie ("Airplane",
List ( "Leslie Nielsen", "Robert Stack"))
, Movie ("Young Frankenstein",
List ("Gene Wilder", "Madeline Kahn"))
, Movie ("The Pink Panther",
List ("Steve Martin", "Jean Reno"))
)
tripleThreat ?A person who has
tripleThreat ?A person who has
Cue, nested loop query...
for (n <- novels;
a <- albums;
m <- movies;
if (n.author == a.artist && m.actors.contains (n.author)))
yield (n.author)
tripleThreat ?A person who has
Cue, nested loop query...
for (n <- novels;
a <- albums;
m <- movies;
if (n.author == a.artist && m.actors.contains (n.author)))
yield (n.author)
Which evaluates to
tripleThreats: List[String] = List(Steve Martin)
You can define a special collection type such that the expression
for (n <- novels;
a <- albums;
m <- movies;
if (n.author == a.artist && m.actors.contains (n.author)))
yield (n.author)
is automatically converted into an SQL (DataBase) query ...!
Elegant way to systematically
Generate Combinations
Search Combinations
Generate & Search Combinations
Given a chess board of size n rows and n columns
Find a placement of n queens so none can kill each other!
Given a chess board of size n rows and columns
Find a placement of n queens so none can kill each other!
The first question: what is a solution ?
The first question: what is a solution ?
We represent each queen by its position XY: a pair of (row, col)
type XY = (Int, Int)
The first question: what is a solution ?
We represent each queen by its position XY: a pair of (row, col)
type XY = (Int, Int)
One queen q1 can kill another q2 if
def canKill(q1: XY, q2: XY) =
q1._1 == q2._1 || // same row
q1._2 == q2._2 || // same column
(q1._1 - q2._1).abs == (q1._2 - q2._2).abs // same diagonal
The first question: what is a solution ?
We represent each queen by its position XY: a pair of (row, col)
type XY = (Int, Int)
One queen q1 can kill another q2 if
def canKill(q1: XY, q2: XY) =
eqRow(q1, q2) || eqCol(q1, q2) || eqDia(q1, q2)
A queen at q is safe w.r.t. other queens if:
def isSafe(queen: XY, others: List[XY]) =
others forall (!canKill(_, queen))
Given a chess board of size n rows and columns
Find a placement of n queens so none can kill each other!
def placeQueens(columns: Int, row: Int) : List[XY]
To place queens on row r ... 0
r-1 ... 0risSafe w.r.t. recursive solutionGiven a chess board of size n rows and columns
Find a placement of n queens so none can kill each other!
r-1...0r !r-1...0r !Given a chess board of size n rows and columns
Find a placement of n queens so none can kill each other!
def placeQueens(columns: Int, row: Int) : List[List[XY]]
To place queens on row r ... 0
r-1 ... 0ryield position which isSafe w.r.t. recursive solutionGiven a chess board of size n rows and columns
Find a placement of n queens so none can kill each other!
def placeQueens(columns: Int, row: Int) : List[List[XY]] =
if (row == 0)
List(List())
else
for { queens <- placeQueens(columns, row - 1)
column <- 1 to columns
queen = (row, column)
if isSafe(queen, queens) }
yield (queen :: queens)
Given a chess board of size n rows and columns
Find a placement of n queens so none can kill each other!
Just printing the 1 solution (of several)
scala> Queens(4, 1)
OOXO
XOOO
OOOX
OXOO
Given a chess board of size n rows and columns
Find a placement of n queens so none can kill each other!
Just printing the 1 solution (there are many)
scala> Queens(8, 1)
OOOXOOOO
OXOOOOOO
OOOOOOXO
OOXOOOOO
OOOOOXOO
OOOOOOOX
OOOOXOOO
XOOOOOOO
Given a chess board of size n rows and columns
Find a placement of n queens so none can kill each other!
scala> Queens(2, 1)
scala> Queens(3, 1)
scala>
5, 3, , , 7, , , ,
6, , , 1, 0, 5, , ,
, 0, 8, , , , , 6,
8, , , , 6, , , , 3
4, , , 8, , 3, , , 1
7, , , , 2, , , , 6
, 6, , , , , 2, 8,
, , , 4, 1, 0, , , 5
, , , , 8, , , 7, 0
5, 3, 4, 6, 7, 8, 0, 1, 2
6, 7, 2, 1, 0, 5, 3, 4, 8
1, 0, 8, 3, 4, 2, 5, 6, 7
8, 5, 0, 7, 6, 1, 4, 2, 3
4, 2, 6, 8, 5, 3, 7, 0, 1
7, 1, 3, 0, 2, 4, 8, 5, 6
0, 6, 1, 5, 3, 7, 2, 8, 4
2, 8, 7, 4, 1, 0, 6, 3, 5
3, 4, 5, 2, 8, 6, 1, 7, 0
The first question: what is a sudoku board ?
The first question: what is a sudoku board ?
We represent each square by its position XY: a pair of (row, col)
type XY = (Int, Int)
The first question: what is a sudoku board ?
We represent each square by its position XY: a pair of (row, col)
type XY = (Int, Int)
We represent the board by a (partial) map from XY to Int
type Board = Map[XY, Int]
5, 3, , , 7, , , ,
6, , , 1, 0, 5, , ,
, 0, 8, , , , , 6,
8, , , , 6, , , , 3
4, , , 8, , 3, , , 1
7, , , , 2, , , , 6
, 6, , , , , 2, 8,
, , , 4, 1, 0, , , 5
, , , , 8, , , 7, 0
is represented by
Map ((0, 0) -> 5, (0, 1) -> 3, (0, 4) -> 7,
(1, 0) -> 6, (1, 3) -> 1, (1, 4) -> 0, (1, 5) -> 5,
(2, 1) -> 0, (2, 2) -> 8, (2, 7) -> 6,
(3, 0) -> 8, (3, 4) -> 6, (3, 8) -> 3,
(4, 0) -> 4, (4, 3) -> 8, (4, 5) -> 3, (4, 8) -> 1,
(5, 0) -> 7, (5, 4) -> 2, (5, 8) -> 6,
(6, 1) -> 6, (6, 6) -> 2, (6, 7) -> 8,
(7, 3) -> 4, (7, 4) -> 1, (7, 5) -> 0, (7, 8) -> 5,
(8, 4) -> 8, (8, 7) -> 7, (8, 8) -> 0)
Given a partially filled Sudoku Board
Find a way to fill in all squares
Given a partially filled Sudoku Board
Find a way to fill in all squares
def solve(b: Board) : Iterator[Board] = {
val blanks = candidates(b)
if (blanks.isEmpty) Iterator(b)
else {
val (xy, choices) = blanks minBy (_._2.length)
for (choice <- choices.toIterator;
bFull <- solve(b + (xy -> choice)))
yield bFull
}
}
def solve(b: Board) : Iterator[Board] = {
val blanks = candidates(b)
if (blanks.isEmpty) Iterator(b)
else {
val (xy, choices) = blanks minBy (_._2.length)
for (choice <- choices.toIterator;
bFull <- solve(b + (xy -> choice)))
yield bFull
}
}
.toIterator call?candidates for a boarddef candidates (b: Board) =
for { x <- 0 until 9 ;
y <- 0 until 9 ;
if (!b.isDefinedAt((x,y))) ;
xy = (x, y) ;
vals = (0 until 9) diff (alreadyTaken(x,y,b)) }
yield (xy, vals)
alreadyTaken values for a squaredef alreadyTaken(x: Int, y: Int, b: Board) =
for (p <- pointsOfCol(x) ++
pointsOfRow(y) ++
pointsOfGrid(x, y)
if b.isDefinedAt(p))
yield b(p)
def pointsOfGrid(x: Int, y: Int) = {
val (x0, y0) = ((x/3) * 3, (y/3) * 3)
for (px <- x0 until x0 + 3 ;
py <- y0 until y0 + 3 )
yield (px, py)
}
def pointsOfCol(x: Int) =
for (y <- 0 until 9) yield (x, y)
def pointsOfRow(y: Int) =
for (x <- 0 until 9) yield (x, y)
Elegant way to systematically
Generate Combinations
Search Combinations
Generate & Search Combinations
Iterator vs. ListIterator vs. ListWe chose Iterator and not List for password crack
words.toList.filter(...).toIterator // yuck
Iterator vs. ListWe chose Iterator and not List for password crack
words.toList.filter(...).toIterator // yuck
words.filter(...) // sweet!
Iterator vs. ListWe chose Iterator and not List for password crack
Iterator lazily computes one element at a timeAt each .next() call
List does)List does)Iterator vs. ListWe chose Iterator and not List for password crack
Iterator lazily computes one element at a timeAt each .next() call
Does not build the entire sequence up at once! (as List does)
Does not store the entire sequence in memory! (as List does)
Iterator good for operating on big data streamsIterator vs. ListIterator is lazy, good for operating on big data streamsdef allVowels(megaDictionary: Iterator[String]): Iterator[String] =
for { w <- megaDictionary
; if hasAllVowels(w) }
yield w
Iterator uses O(1) memory (at any given time) ...def allVowels(megaDictionary: List[String]): List[String] =
for (w <- megaDictionary
if hasAllVowels(w))
yield w
List uses O(N) memory, where N = megaDictionary size.Iterator vs. ListWe chose Iterator and not List for password crack
Iterator is lazy, good for operating on big data streamsdef txReverse(megaDictionary: Iterator[String]): Iterator[String] =
for (w <- megaDictionary
c <- Iterator(w, reverse(w))
yield c
Iterator uses O(1) memory (at any given time) ...def txReverse(megaDictionary: List[String]): List[String] =
for (w <- megaDictionary
c <- Iterator(w, reverse(w))
yield c
List uses O(N) memory, where N = megaDictionary size.Iterator vs. ListWe chose Iterator and not List for password crack
Iterator is lazy, good for operating on big data streamsIterator ?IteratorFor PA5
for and yield and HOFSIterator to List