Scala for the Impatient -- 2nd Edition


Chapter 3. Working with Arrays


In [1]:
println(s"""Details of exec env ==>
    |    ${util.Properties.versionMsg}
    |    ${util.Properties.javaVmName} ${util.Properties.javaVersion} ${util.Properties.javaVmVersion}"""
.stripMargin)


Details of exec env ==>
    Scala library version 2.11.8 -- Copyright 2002-2016, LAMP/EPFL
    Java HotSpot(TM) 64-Bit Server VM 1.8.0_131 25.131-b11

Qn#1. Write a code snippet that sets a to an array of n random integers between 0 (inclusive) and n (exclusive).


In [2]:
import math._

val n = 10
val random = scala.util.Random
val a  = for (i <- 0 until n) yield random.nextInt(n)
a


Out[2]:
Vector(5, 2, 2, 6, 6, 5, 3, 4, 3, 2)

Qn#2. Write a loop that swaps adjacent elements of an array of integers. For example, Array(1, 2, 3, 4, 5) becomes Array(2, 1, 4, 3, 5)


In [3]:
val array = Array(1, 2, 3, 4, 5)

array.grouped(2).flatMap(_.reverse).toArray

//array.grouped(2).map(_.reverse).flatMap(n => n).toArray


Out[3]:
Name: Syntax Error.
Message: 
StackTrace: 

Qn#3. Repeat the preceding assignment, but produce a new array with the swapped values. Use for / yield.


In [4]:
(for {x <- array.grouped(2); y <- x.reverse} yield y).toArray


Out[4]:
Array(2, 1, 4, 3, 5)

Qn#4. Given an array of integers, produce a new array that contains all positive values of the original array, in their original order, followed by all values that are zero or negative, in their original order.


In [5]:
val array = Array(-9, 0, 2, -22, 5)

val (a,b) = array.partition( _ > 0)
a ++ b


Out[5]:
Array(2, 5, -9, 0, -22)

Qn#5. How do you compute the average of an Array[Double]?


In [6]:
val array = Array(9.43, -10.26, -0.9921, 15.09, 27.812, 1.56)

array.sum/array.length


Out[6]:
7.106650000000001

Qn#6. How do you rearrange the elements of an Array[Int] so that they appear in reverse sorted order? How do you do the same with an ArrayBuffer[Int]?


In [7]:
val array = Array(-9, 0, 2, -22, 5)

array.sortWith( _ > _)


Out[7]:
Array(5, 2, 0, -9, -22)

In [8]:
// For ArrayBuffer
val arrayBuffer = array.toBuffer

arrayBuffer.sortWith( _ > _)


Out[8]:
ArrayBuffer(5, 2, 0, -9, -22)

Qn#7. Write a code snippet that produces all values from an array with duplicates removed. (Hint: Look at Scaladoc.)

Solution#1


In [9]:
val array = Array(7, 1, 12, 0, 1, 20, 1, 12, 8, 1, 2, 9, 0)

array.distinct


Out[9]:
Array(7, 1, 12, 0, 20, 8, 2, 9)

Solution#2


In [10]:
val array = Array(7, 1, 12, 0, 1, 20, 1, 12, 8, 1, 2, 9, 0)

array.toSet


Out[10]:
Set(0, 20, 1, 9, 2, 12, 7, 8)

Solution#3


In [11]:
val array = Array(7, 1, 12, 0, 1, 20, 1, 12, 8, 1, 2, 9, 0)

val b = Array[Int]().toBuffer

for(i <- array; if !(b contains i)) b += i

b


Out[11]:
ArrayBuffer(7, 1, 12, 0, 20, 8, 2, 9)

Qn#8. Suppose you are given an array buffer of integers and want to remove all but the first negative number. Here is a sequential solution that sets a flag when the first negative number is called, then removes all elements beyond.

var first = true
var n = a.length
var i = 0
while (i < n) {
  if (a(i) >= 0) i += 1
  else {
    if (first) { 
        first = false; 
        i += 1
    }
    else { 
        a.remove(i); 
        n -= 1
    }
  }
}

This is a complex and inefficient solution. Rewrite it in Scala by collecting positions of the negative elements, dropping the first element, reversing the sequence, and calling a.remove(i) for each index.

Actually this solution performs better than the other solutions here.


In [12]:
// Original: "complex and inefficient solution", but this performs better compared to the solutions below.
val a = Array(1, 9, 121, 71, 21, -5, 15, 0, -20, 10, -6, 9, 20, -2).toBuffer

var first = true
var n = a.length
var i = 0
while (i < n) {
  if (a(i) >= 0) i += 1
  else {
    if (first) { 
        first = false; 
        i += 1
    }
    else { 
        a.remove(i); 
        n -= 1
    }
  }
}
a


Out[12]:
ArrayBuffer(1, 9, 121, 71, 21, -5, 15, 0, 10, 9, 20)

Solution#1


In [13]:
val a = Array(1, 9, 121, 71, 21, -5, 15, 0, -20, 10, -6, 9, 20, -2).toBuffer

val b = a.zipWithIndex.filter { case (elem, i) => 
    elem < 0
}

b.remove(0)

val c = b.zipWithIndex.map { case (elem, i) => 
    a.remove(elem._2 - i) 
}

a


Out[13]:
ArrayBuffer(1, 9, 121, 71, 21, -5, 15, 0, 10, 9, 20)

Solution#2


In [14]:
val a = Array(1, 9, 121, 71, 21, -5, 15, 0, -20, 10, -6, 9, 20, -2).toBuffer

val b = a.zipWithIndex.filter(_._1 < 0)

b.remove(0)
val c = b.reverse

val d = c.map { case(_, i) => 
    a.remove(i)
}

a


Out[14]:
ArrayBuffer(1, 9, 121, 71, 21, -5, 15, 0, 10, 9, 20)

Qn#9. Improve the solution of the preceding exercise by collecting the positions that should be moved and their target positions. Make those moves and truncate the buffer. Don’t copy any elements before the first unwanted element.


In [15]:
println("TBC")


TBC

Qn#10. Make a collection of all time zones returned by java.util.TimeZone.getAvailableIDs that are in America. Strip off the America/ prefix and sort the result.


In [16]:
val lenToDrop = "America/".length
java.util.TimeZone.getAvailableIDs.filter(_.startsWith("America/")).map(_.drop(lenToDrop)).foreach(println) // No need to sort, it is already sorted.


Adak
Anchorage
Anguilla
Antigua
Araguaina
Argentina/Buenos_Aires
Argentina/Catamarca
Argentina/ComodRivadavia
Argentina/Cordoba
Argentina/Jujuy
Argentina/La_Rioja
Argentina/Mendoza
Argentina/Rio_Gallegos
Argentina/Salta
Argentina/San_Juan
Argentina/San_Luis
Argentina/Tucuman
Argentina/Ushuaia
Aruba
Asuncion
Atikokan
Atka
Bahia
Bahia_Banderas
Barbados
Belem
Belize
Blanc-Sablon
Boa_Vista
Bogota
Boise
Buenos_Aires
Cambridge_Bay
Campo_Grande
Cancun
Caracas
Catamarca
Cayenne
Cayman
Chicago
Chihuahua
Coral_Harbour
Cordoba
Costa_Rica
Creston
Cuiaba
Curacao
Danmarkshavn
Dawson
Dawson_Creek
Denver
Detroit
Dominica
Edmonton
Eirunepe
El_Salvador
Ensenada
Fort_Nelson
Fort_Wayne
Fortaleza
Glace_Bay
Godthab
Goose_Bay
Grand_Turk
Grenada
Guadeloupe
Guatemala
Guayaquil
Guyana
Halifax
Havana
Hermosillo
Indiana/Indianapolis
Indiana/Knox
Indiana/Marengo
Indiana/Petersburg
Indiana/Tell_City
Indiana/Vevay
Indiana/Vincennes
Indiana/Winamac
Indianapolis
Inuvik
Iqaluit
Jamaica
Jujuy
Juneau
Kentucky/Louisville
Kentucky/Monticello
Knox_IN
Kralendijk
La_Paz
Lima
Los_Angeles
Louisville
Lower_Princes
Maceio
Managua
Manaus
Marigot
Martinique
Matamoros
Mazatlan
Mendoza
Menominee
Merida
Metlakatla
Mexico_City
Miquelon
Moncton
Monterrey
Montevideo
Montreal
Montserrat
Nassau
New_York
Nipigon
Nome
Noronha
North_Dakota/Beulah
North_Dakota/Center
North_Dakota/New_Salem
Ojinaga
Panama
Pangnirtung
Paramaribo
Phoenix
Port-au-Prince
Port_of_Spain
Porto_Acre
Porto_Velho
Puerto_Rico
Punta_Arenas
Rainy_River
Rankin_Inlet
Recife
Regina
Resolute
Rio_Branco
Rosario
Santa_Isabel
Santarem
Santiago
Santo_Domingo
Sao_Paulo
Scoresbysund
Shiprock
Sitka
St_Barthelemy
St_Johns
St_Kitts
St_Lucia
St_Thomas
St_Vincent
Swift_Current
Tegucigalpa
Thule
Thunder_Bay
Tijuana
Toronto
Tortola
Vancouver
Virgin
Whitehorse
Winnipeg
Yakutat
Yellowknife

Qn#11. Import java.awt.datatransfer._ and make an object of type SystemFlavorMap with the call.

val flavors = SystemFlavorMap.getDefaultFlavorMap().asInstanceOf[SystemFlavorMap]

Then call the getNativesForFlavor method with parameter DataFlavor.imageFlavor and get the return value as a Scala buffer. (Why this obscure class? It’s hard to find uses of java.util.List in the standard Java library.)


In [17]:
import java.awt.datatransfer._

val flavors = SystemFlavorMap.getDefaultFlavorMap().asInstanceOf[SystemFlavorMap]
flavors.getNativesForFlavor(DataFlavor.imageFlavor)


Out[17]:
[PNG, JFIF]