It all seemed so straightforward at first. And it was. Until I needed to split an array into key value pairs for the second excercise. I spent about two hours trying to find a nice way f doing that. I’m not entirely happy with the way I came up with, but it works at least.
The scala syntax and especially the type system seemed determined not to let me write something simple as I would in Perl, say
my %wordhash = map { split / / } @lines
I am sure there is a nice clean way to do it in Scala, but I’ve not found it. Hey ho. Other than that the tasks were fairly straightforward and actually sorta fun. I did find that the syntax felt a little alien to me, and I spent a lot of time battling the type system rather than thinking about my meaning. But I guess that is something that is inevitable when learning a new language.
string_sum.scala
Use foldLeft to compute the total size of a list of strings
I thought that this meant the total length of all the strings in the list of strings. Which is pedantic of me. I rather liked the :/ form of foldLeft. Which probably has something to do with having a Perl background. Here is the code anyhow:
$ cat string_sum.scala
val words = List ("plinth"
, "antediluvian"
, "moist"
, "recalcitrance"
, "flange"
, "ashanti"
)
val total_length = (0 /: words) { (sum, word) => sum + word.size }
println("Total word length is: " + total_length)
Running this code gives me:
$ scala string_sum.scala
Total word length is: 49
Is that right? I’ll use a bit of perl and bash to check:
$ cat string_sum.scala | perl -ne 'next unless /"/; next if /Total/; s/.*"([^"]+)"/$1/; s/[\r\n]//g; print' | wc -c
49
Super. Job done.
censor.scala
- Write a Censor trait with a method that will replace the curse words Shoot and Darn with Pucky and Beans alternatives. Use a map to store the curse words and their alternatives.
- Load the curse words and alternatives from a file
I think my implementation is OK, though the k->v splitting felt kludgey to me and the CensoredWords class doesn't seem totally necessary. Traits are a good thing, so I’m glad of having had the chance to hack one.
trait Censor {
val badWordFile = "badwords.txt"
var badWords = Map(
"shoot" -> "pucky",
"darn" -> "beans"
)
// passed a List of words
// return censored word list
def censorList (wordList: List[String]): List[String] = {
// using the ternary-like construct again and filter as described in the book
// also contains method as per http://www.scala-lang.org/api/current/scala/collection/immutable/Map.html
wordList.map(word =>
if(badWords.contains(word)) badWords(word) else word
)
}
// passed a String to censor
// returns a censored String
def censorString (wordString: String): String = {
// I used split(" ").toList() to split the String into a list. Not sure toList is necessary.
// and mkString to rejoin the censored list returned by CensorList
// (cf: http://www.scala-lang.org/api/2.7.5/scala/Iterable.html#mkString(String))
// Scala has a perlish implicit return so I rely on that to return
censorList(List.fromArray(wordString.split(" "))).mkString(" ")
}
// Read badwords from badWordFile
def readBadWordsFromFile() {
// hints on Map from http://langref.org/scala/maps
var badWordMap = Map.empty[String,String]
val lines = scala.io.Source.fromFile(badWordFile).getLines
// This was physically painful to write, tried about a million approaches.
// It still feels kludgey and not elegant.
lines.foreach( line => {
line.split(" ") match {
case Array(k,v) => {
badWordMap += k -> v.trim
}
}
}
)
badWords = badWordMap
}
}
class Words(val data: String) {
def getData(): String = {
data
}
}
class CensoredWords(override val data: String) extends Words(data) with Censor {
def getPolite(): String = {
readBadWordsFromFile()
censorString(data)
}
}
val c=new CensoredWords("I want to shoot the motherfucker.")
println(c.getPolite())
As you can probably spot I have a badwords.txt text file with the following in it as the data source:
$ cat badwords.txt
shoot pucky
darn beans
Well, an interesting day and a good illustration of some functional constructs. If it hadn't been for wrestling with the syntax and the type system it would have been even funner.