public
Last active

  • Download Gist
ListComputations.scala
Scala
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
// 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)

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.