Scala for the Impatient

Cay S. Horstmann

Mentioned 4

Presents an introduction to the Scala programming language which is an abbreviated version of object-orientated programming combined with the power of concurrency capable of running on the Java Virtual Machine.

More on Amazon.com

Mentioned in questions and answers.

While going through the book Scala for the Impatient, I came across this question:

Come up with one situation where the assignment x = y = 1 is valid in Scala. (Hint: Pick a suitable type for x.)

I am not sure what exactly the author means by this question. The assignment doesn't return a value, so something like var x = y = 1 should return Unit() as the value of x. Can somebody point out what might I be missing here?

Thanks

In fact, x is Unit in this case:

var y = 2
var x = y = 1

can be read as:

var y = 2
var x = (y = 1)

and finally:

var x: Unit = ()

While trying to run the following snippet from Scala for the impatient:

val b = ArrayBuffer(1,7,2,9)
val bSorted = b.sorted(_ < _)

I get the following error:

 error: missing parameter type for expanded function ((x$1, x$2) => x$1.$less(x$2))
       val bSorted = b.sorted(_ < _)

Can somebody explain what might be going on here. Shouldn't the parameter type be inferred from the contents of the ArrayBuffer or do I need to specify it explicitly?

Thanks

.sorted takes an implicit parameter of type Ordering (similar to Java Comparator). For integers, the compiler will provide the correct instance for you:

scala> b.sorted
res0: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 7, 9)

If you want to pass a comparison function, use sortWith:

scala> b.sortWith( _ < _ )
res2: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 7, 9)

scala> b.sortWith( _ > _ )
res3: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(9, 7, 2, 1)

However, pay attention, although ArrayBuffer is mutable, both sort methods will return a copy which is sorted, but the original won't be touched.

I am trying to solve the following problem from Scala for the impatient. The question is as follows:

Using pattern matching, write a function swap that swaps the first two elements of an array provided its length is at least two.

My solution is:

def swap(sArr:Array[Int]) = sArr.splitAt(2) match { 
                               case (Array(x,y),Array(z)) => Array(y,x,z)
                               case (Array(x,y),Array()) => Array(y,x)
                               case _ => sArr
                            }

My problem is with the first case statement. I think it would pattern-match something like (Array(1,2),Array(3)) whereas I intend it to pattern-match (Array(1,2),Array(3,4,5.....))

Can somebody point out how that would be possible.

Thanks

The problem with your code is that Array(z) means "match a one-element array". What you want is for z to be the whole array, no matter how many elements:

def swap(sArr: Array[Int]) = 
  sArr.splitAt(2) match { 
    case (Array(x, y), z) => Array(y, x) ++ z
    case _ => sArr
}

However, I would write it with the sequence-matching syntax _* so that you don't have to manually split the array:

def f(a: Array[Int]) = 
  a match {
    case Array(x, y, z @ _*) => Array(y, x) ++ z
    case _ => a
}

This problem appeared under "Maps and Tuples" Chapter in Scala for the Impatient

  1. Write a program that reads words from a file. Use a mutable map to count how often each word appears.

My attempt is

// source file: https://www.gutenberg.org/cache/epub/35709/pg35709.txt 
scala> val words = scala.io.Source.fromFile("pg35709.txt").mkString.split("\\s+")
words: Array[String] = Array(´╗┐The, Project, Gutenberg, EBook, of, Making, Your, Camera, Pay,, by, Frederick, C., Davis, 
This, eBook, is, for, the, use, of, anyone, anywhere, at, no, cost, and, with, almost, no, restrictions, whatsoever., 
You, may, copy, it,, give, it, away, or, re-use, it, under, the, terms, of, the, Project, Gutenberg, License, included, 
with, this, eBook, or, online, at, www.gutenberg.net, Title:, Making, Your, Camera, Pay, Author:, Frederick, C., Davis, 
Release, Date:, March, 29,, 2011, [EBook, #35709], Language:, English, ***, START, OF, THIS, PROJECT, GUTENBERG, EBOOK, 
MAKING, YOUR, CAMERA, PAY, ***, Produced, by, The, Online, Distributed, Proofreading, Team, at, http://www.pgdp.net, 
(This, file, was, produced, from, images, generously, made, available, by, The, In... 

scala> val wordCount = scala.collection.mutable.HashMap[String, Int]()
wordCount: scala.collection.mutable.HashMap[String,Int] = Map()

scala> for (word <- words) {
     | val count = wordCount.getOrElse(word, 0)
     | wordCount(word) = count + 1
     | }

scala> word
wordCount   words

scala> wordCount
res1: scala.collection.mutable.HashMap[String,Int] = Map(arts -> 1, follow -> 3, request, -> 1, Lines. -> 1, 
demand -> 7, 1.E.4. -> 1, PRODUCT -> 2, 470 -> 1, Chicago, -> 3, scenic -> 1, J2 -> 1, untrimmed -> 1, 
photographs--not -> 1, basis. -> 1, "prints -> 1, instances. -> 1, Onion-Planter -> 1, trick -> 1, 
illustrating -> 3, prefer. -> 1, detected -> 1, non-exclusive. -> 1, famous -> 1, Competition -> 2, 
expense -> 1, created -> 2, renamed. -> 1, maggot -> 1, calendar-photographs, -> 1, widely-read -> 1, 
Publisher, -> 1, producers -> 1, Shapes -> 1, ARTICLES -> 2, yearly -> 2, retoucher -> 1, satisfy -> 2, 
agrees: -> 1, Gentleman_, -> 1, intellectual -> 2, hard -> 2, Porch. -> 1, sold.) -> 1, START -> 1, House -> 2, 
welcome -> 1, Dealers' -> 1, ... -> 2, pasted -> 1, _Cosmopolitan_ -...

While I know that this works, I wanted to know if there is Scalaesque way of achieving the same

You can do this:

val wordCount = words.groupBy(w => w).mapValues(_.size)

The groupBy method returns a map from the result of the given function, to a collection of values that return the same value from the function. In this case, a Map[String, Array[String]]. Then mapValues maps the Array[String] to their lengths.