Skip to content

Instantly share code, notes, and snippets.

@jasonbaldridge
Last active September 30, 2015 16:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jasonbaldridge/1830413 to your computer and use it in GitHub Desktop.
Save jasonbaldridge/1830413 to your computer and use it in GitHub Desktop.
// This is code to accompany my blog post about variations on sequence computations:
// http://bcomposes.wordpress.com/2012/02/14/variations-for-computing-results-from-sequences-in-scala/
//
// Jason Baldridge
// A function to display the results of various ways of doing the same thing.
def display (intro: String, wlengths: List[Int], wcaps: List[Boolean]) {
println(intro)
println("Lengths: " + wlengths.mkString(" "))
println("Caps: " + wcaps.mkString(" "))
println
}
// The list of words to use.
val words = List("This", "is", "a", "list", "of", "English", "words", ".")
// *****************************************************************************
// The functional way
val (wlengthsMapUnzip, wcapsMapUnzip) =
words.map(word => (word.length, word(0).isUpper)).unzip
display("Using map and unzip.",
wlengthsMapUnzip, wcapsMapUnzip)
// *****************************************************************************
// Using reassignable lists
var wlengthsReassign = List[Int]()
var wcapsReassign = List[Boolean]()
words.foreach { word =>
wlengthsReassign = word.length :: wlengthsReassign
wcapsReassign = word(0).isUpper :: wcapsReassign
}
display("Using reassignable lists.",
wlengthsReassign.reverse, wcapsReassign.reverse)
// *****************************************************************************
// Using a mutable ListBuffer
import collection.mutable.ListBuffer
val wlengthsBuffer = ListBuffer[Int]()
val wcapsBuffer = ListBuffer[Boolean]()
words.foreach { word =>
wlengthsBuffer.append(word.length)
wcapsBuffer.append(word(0).isUpper)
}
display("Using mutable ListBuffer.",
wlengthsBuffer.toList, wcapsBuffer.toList)
// *****************************************************************************
// The imperative way
val wlengthsArray = Array.fill(words.length)(0)
val wcapsArray = Array.fill(words.length)(false)
words.indices.foreach { index =>
wlengthsArray(index) = words(index).length
wcapsArray(index) = words(index)(0).isUpper
}
display("Using iteration and arrays.", wlengthsArray.toList, wcapsArray.toList)
// *****************************************************************************
// The imperative way without the cost of indexing into Lists
val wlengthsArray2 = Array.fill(words.length)(0)
val wcapsArray2 = Array.fill(words.length)(false)
var index = 0
words.foreach { word =>
wlengthsArray2(index) = word.length
wcapsArray2(index) = word(0).isUpper
index += 1
}
// *****************************************************************************
// As above, but using zipWithIndex to iterate over (word,index) pairs.
val wlengthsArray3 = Array.fill(words.length)(0)
val wcapsArray3 = Array.fill(words.length)(false)
words.zipWithIndex.foreach { case(word,index) =>
wlengthsArray3(index) = word.length
wcapsArray3(index) = word(0).isUpper
}
// *****************************************************************************
// Using a predefined function
def getLengthAndUpper = (word: String) => (word.length, word(0).isUpper)
val (wlengthsFunction, wcapsFunction) = words.map(getLengthAndUpper).unzip
display("Using a predefined function.",
wlengthsFunction.toList, wcapsFunction.toList)
// *****************************************************************************
// Using for expressions
val (wlengthsFor, wcapsFor) =
(for (word <- words) yield (word.length, word(0).isUpper)).unzip
display("Using a for expression.",
wlengthsFunction.toList, wcapsFunction.toList)
// *****************************************************************************
// Using a recursive function
// This is a recursive function that builds up the lengths and caps lists.
def lengthCapRecursive(
inputWords: List[String],
lengths: List[Int],
caps: List[Boolean]): (List[Int], List[Boolean]) = inputWords match {
case Nil =>
(lengths, caps)
case head :: tail =>
lengthCapRecursive(tail, head.length :: lengths, head(0).isUpper :: caps)
}
// This is a "wrapper" for the above recursive functin that calls that function
// with empty lists, gets the results, and returns the reverse of each list.
def lengthCapRecursive(inputWords: List[String]): (List[Int], List[Boolean]) = {
val (l,c) = lengthCapRecursive(words, List[Int](), List[Boolean]())
(l.reverse, c.reverse)
}
val (wlengthsRecursive, wcapsRecursive) = lengthCapRecursive(words)
display("Using a recursive function.",
wlengthsRecursive, wcapsRecursive)
// *****************************************************************************
// Using a recursive function that is contained in the wrapper function
def lengthCapRecurWrap(inputWords: List[String]): (List[Int], List[Boolean]) = {
// This function is hidden from code that doesn't
def lengthCapRecurHelp(
inputWords: List[String],
lengths: List[Int],
caps: List[Boolean]): (List[Int], List[Boolean]) = inputWords match {
case Nil =>
(lengths, caps)
case head :: tail =>
lengthCapRecurHelp(tail, head.length :: lengths, head(0).isUpper :: caps)
}
val (l,c) = lengthCapRecurHelp(words, List[Int](), List[Boolean]())
(l.reverse, c.reverse)
}
val (wlengthsRecurWrap, wcapsRecurWrap) = lengthCapRecurWrap(words)
display("Using a recursive function contained in a wrapper.", wlengthsRecurWrap, wcapsRecurWrap)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment