[Scala] Vector, List, Array, Map, String

Screen Shot 2014-10-15 at 11.52.52 AM

Array(0), Array.size, Array.indexOf(“first_element”), Array.mkString(“:”), Array.ofDim[Int](5) => Array[Int] = Array(0, 0, 0, 0, 0)

val two_dimensional = Array.ofDim[Int](2, 3) => Array[Array[Int]] = Array(Array(0, 0, 0), Array(0, 0, 0))

val elaimet = Vector(laama, alpakka, vinkuja)

elaimet: Vector[String] = Vector(laama, alpakka, vinkuja)

elaimet.zipWithIndex

res0: Vector[(String, Int)] = Vector((laama, 0), (alpakka, 1), (vinkuja, 2)).zipWithIndex

res1: IndexedSeq[(Char, Int)] = Vector((g, 0), (u, 1), (a, 2), (n, 3), (a, 4), (k, 5), (o, 6))

Vector Methods

Vector(1,2,3,4).max => 4
Vector("a", "bb", "b").max => bb

Vector(0, -34, 102).sorted => Vector(-34, 0, 102)
Vector(0, -34, 102).sorted.reverse => Vector(102, 0, -34)
Vector("a", "bb", "b", "aaa").maxBy( _.length ) => aaa
Vector(0, -3, 2).maxBy( pow(_, 2) ) => 2
Vector("a", "bb", "b", "aaa").sortBy( _.length )
Vector(0, -3, 2).sortBy( pow(_, 2) )
zip-method

val korkeudet = Vector(180, 80, 60)

korkeudet: Vector[Int] = Vector(180, 80, 60)

val korkeudetJaLajit = korkeudet.zip(elaimet)

korkeudetJaLajit: Vector[(Int, String)] = Vector((180, laama), (80, alpakka), (60, vinkuja))

"laama".zip("kissa")

res2: IndexedSeq[(Char, Char)] = Vector((l, k), (a, i), (a, s), (m, s), (a, a))

korkeudetjaLajit.unzip

res3: (Vector[Int], Vector[String]) = (Vector(180, 80, 60), Vector(laama, alpakka, vinkuja))

Converting Char to Int

'1'.asDigit

res0 = Int 1
Map, which works like dictionary in Python
val phonebook = Map("Seyoung" -> "123445", "Ryung" -> "6543w2")
phonebook += ("James" -> "23939405")
println(phonebook("Seyoung"))
import scala.collection.mutable.Map
val suomestaEnglanniksi = Map("kissa" -> "cat", "laama" -> "Ilama")
suomestaEnglanniksi.get("kissa")
=> Option[String] = Some(cat)
suomestaEnglanniksi.get("Johnny Depp")
=> Option[String] = None

suomestaEnglanniksi -= "cat"  // Delete the item
suomestaEnglanniksi.remove("cat")
suomestaEnglanniksi.contains("laama") => true
suomestaEnglanniksi.contains("Johnny") => false

How to Print items from Map

suomestaEnglanniksi.keys.foreach(println)
suomestaEnglanniksi.values.foreach(println)

suomestaEnglanniksi.mapValues( _.toUpperCase )
=> Map(kissa -> CAT, koira -> DOG)
suomestaEnglanniksi.mapValues( _.length )
=> Map(kissa -> 5, koira -> 3)

Familiar methods with Map

suomestaEnglanniksi.isEmpty => false
suomestaEnglanniksi.size => 3
suomestaEnglanniksi.foreach(println) => Prints both keys and values
suomestaEnglanniksi.getOrElseUpdate("koulu", "school") 
=> Adds a new value if "koulu" is not found

Default value for Map

val newDic = Map("kissa" -> "cat", "tapiiri" -> "tapir").withDefaultValue("tuntematon")
newDic.get("kissa") => Some(cat)
newDic.get("puppy") => Some(tuntematon)

Declare a Map from a class

class Asiakas(val numero: Int, val nimi: String, val syntynyt: Int, val kuollut: Option[Int]) {
override def toString = this.nimi + "(" + this.syntynyt + "-" + kuollut.getOrElse("") + ")"}

asiakasluettelo.map( asiakas => asiakas.numero -> asiakas )
=> Creates a Vector of key - value pairs.

val asiakashakemisto = asiakasluettelo.map( asiakas => asiakas.numero -> asiakas ).toMap
=> Creates a Map
asiakasluettelo.groupBy( _.syntynyt / 100 )
=> Map(14 -> Vector(Michelangelo(1475-1564)))

Better class to create a Map

class Asiakasrekisteri(val nimi: String) {

 private val asiakkaat = Map[Int, Asiakas]()

 def lisaa(uusiAsiakas: Asiakas) = {
 this.asiakkaat(uusiAsiakas.numero) = uusiAsiakas
 }

 def hae(asiakasnumero: Int) = this.asiakkaat.get(asiakasnumero)

}

Accessing keys and values from a Pair

val example = "koira" -> "dog"
example._1 => koira
example._2 => dog

Pair tricks

val pair = (5, 2)
val (left, right) = pair
left: Int = 5
right: Int = 2

Order by the cardinality of values

val countsForEachDirector = groupByDirector.mapValues( _.size )
=> Maps to the total number of their works
 
val directorCountPairs = countsForEachDirector.toVector
=> Convert the map to a vector

directorCountPairs(0)._1
=> Accessing the name of the director in the first index

val directorsSorted = directorCountPairs.sortBy( pair => -pair._2)
=> The director with the most work comes first

Swapping elemnts in Pair

val pair = "key" -> "value"
pair.swap  // (String, String) = (value, key)

Swapping elemnts in Map

val finnEng = Map("kissa" ->"cat, "koira"->"dog", "laama"->"llama")
val engFinn = finnEng.map( _.swap )  

Capitalizing initial letter in Map values

val words = Map("kissa" ->"cat, "koira"->"dog", "laama"->"llama")
words.mapValues( englishWord => englishWord.head.toUpper + englishWord.tail )
// Map[String, String] = Map(kissa -> Cat, koira -> Dog, laama -> Llama)
words.map( pair => (pair._1.head.toUpper + pair._1.tail) -> (pair._2.head.toUpper + pair._2.tail) )

Tricks with case and for-yield

val words = Map("kissa" ->"cat, "koira"->"dog", "laama"->"llama")
words.map( { case (fin, eng) => fin.capitalize -> eng.capitalize } )
// capitalize is a manually defined function. it checkes
// case(fin, eng) means, if there would be two parameters, do blah blah blah</pre>
<pre>for ((fin, eng) <- words) yield fin.capitalize -> eng.capitalize

tupled – helper function

import Function.tupled
words.map(tupled( _.capitalize -> _.capitalize ))
// Here you don't need to use ._1 and ._2

Using your own function

mapPairs(words)( _.capitalize )
def mapPairs[Orig, New](source: Map[Orig, Orig])(f: Orig => New) =
  for ((key, value) <- source) yield f(key) -> f(value)

takeWhile, drop

/* Let's swap these words by first vowels.
 * "schirl", "gool"
 * Assume there is a helper function: isConsonant() which tells
 * whether it is a consonant or not.
 */
class Word(val word: String) {
 val head = word.takeWhile( this.isConsonant(_) )
 val vowel = word(head.length)
 val vowels = word.drop(head.length).takeWhile( _ == vowel)
 val tail = word.drop(head.length + vowels.length)

 private def isConsonant(i: Char): Boolean = {
 val consonants = "qwrtpsdfghjklzxcvbnm"
 consonants.contains(i)
 }
 private def partialSwap(another: Word): String = {
 this.head + this.vowels + another.tail
 }

 def swap(another: Word): String = {
 this.partialSwap(another) + " " + another.partialSwap(this)
 }
}

object Word extends App{
 println(new Word("school").swap(new Word("girl")))
}


Accessing a Char in a String

"Seyoung"(0) // will give 'S'
"Seyoung".charAt(0) // Will also give 'S'

Playing with Strings

"Hello World".filter( _.isLower ) // "elloorld"
"Hello World".sorted // "HWdellloor
"Hello World".sortBy( _.toLower ) // "dellloorHW"
"Hello World".map( t => if(t.isLower) t.toUpper else t.toLower )
// "hELLO wORLD"
"Hei".map( _.isLower) // Vector(false, true, true)

 Create a Scala List


val list = List(1,2,3)    // x:List[Int] = List(1,2,3)

val x = List[Number](1, 2.0, 33d, 0x1)
// x: List[java.lang.Number] = List(1, 2.0, 33.0, 1)

val x = List.range(1, 10)
x: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)

val x = List.range(0, 10, 2)
x: List[Int] = List(0, 2, 4, 6, 8)

scala> val x = List.fill(3)("foo")
x: List[java.lang.String] = List(foo, foo, foo)

scala> val x = List.tabulate(5)(n => n * n)
x: List[Int] = List(0, 1, 4, 9, 16)

Vectors: How to add an element

val lukuja = Vector(5, 1, 2)
lukuja: Vector[Int] = Vector(5, 1, 2)
val isompi = lukuja :+ 10
isompi: Vector[Int] = Vector(5, 1, 2, 10)
isompi.foreach(n => println(n*n))
25
1
4
100
isompi.exists( _ < 5)
true
isompi.exists( _ < 0 )
false
isompi.forall( _ > 0 )
true
isompi.forall( _ > 10 )
false
isompi.find( _ < 5)
1    // Finds the first element that is less than 5
isompi.filter( _ > 2 )
Vector[Int] = Vector(5, 10)
isompi.foldLeft(0)( (sumSoFar, next) => sumSoFar + next)
Int: 18
isompi.foldLeft(0)( _ + _ )
Int: 18
isompi.foldLeft(1)( _ * _ )
Int: 100
isompi.foldLeft(false)( (foundYet, next) => foundYet || next < 0)
Boolean = false
isompi.foldLeft(false)( _ || _ < 0)
Boolean = false
isompi.reduceLeft(min(_, _))
Int: 1
isompi.reduceLeft(min)
Int: 1
/* reduceLeft is more compact than foldLeft method.
 * However reduceLeft must have one element with in the given collection.
 * foldLeft doesn't necessarily need any element since the initial element is manually 
 * given.
*/

val luvut = Vector(10, 5, 4, 5, -20)
luvut.map( _.abs)
Vector[Int] = Vector(10, 5, 4, 5, 20)
luvut.map( _ >= 5 )
Vector[Boolean] = Vector(true, true, false, true, false)
(1 to 10).map( n => n * n )
IndexedSeq[Int] = Vector(1, 4, 9, 16, ..... , 100)
val animal = Vector("cat", "sheep", "tiger", "lion")
animal.map( _.length )
Vector[Int] = Vector(3, 5, 5, 4)
val ex = Vector(Vector(3, -10, -4), Vector(5, 3, -2), Vector(-5, 100, -324))
ex.flatten
Vector[Int] = Vector(3, -10, -4, 5, 3, -2, -5, 100, -342)

luvut.flatmat( n => (-n.abs, 0, n.abs) )
Vector[Int] = Vector(-10, 0, 10, -5, 0, 5, .... -20, 0, 20)

Scala is Flexible

luvut.filter( _ > 0 ).map(n => n * n). count( _ % 2 === 0)
// This is equal to
luvut.filter { _ > 0 } map {n => n * n} count{ _ % 2 === 0}

Example: users and addresses

class User(val id: String, val address: Vector[String]) {
    override def toString = this.id + " <" + this.address.mkString(",") + ">"
}

val allUsers = Vector(
  new User("Iris", Vector("iris.K@aalto.fi", "iris.k@gmail.com", iris.k@yahoo.com")),
  new User("Jay", Vector("jay@aalto.fi", "jay@gmail.com", jay.k@yahoo.com")),
)

allUsers.map(_.address)
Vector[Vector[String]] = Vector(Vector(iris.K@aalto.fi, iris.k@gmail.com, iris.k@yahoo.com), Vector(jay@aalto.fi, jay@gmail.com, jay.k@yahoo.com))

allUsers.flatMap(_.address)
Vector[String] = Vector(iris.K@aalto.fi, iris.k@gmail.com, iris.k@yahoo.com, jay@aalto.fi, jay@gmail.com, jay.k@yahoo.com)

Options! Some(Int)…..

val luvut = Vector(10, 5, 4, 5, -20)
val isoJosLoytyi = luvut.find( _ > 10000 )
val negatiivinenJosLoytyi = luvut.find( _ < 0 )
val isonParillisuus = if (isoJosLoytyi.isDefined) Some(isoJosLoytyi.get % 2 == 0) else None

val test = Some(100)
test.foreach(println)  ==> 100
test.exists( _ == 50 )
Boolean = false
test.exists( _ > 0 )
Boolean = true
test.forall( _ > 0 )
Boolean = true
test.map( 2 * scala.math.Pi * _ )
Option[Double] = Some(628.318....)

val test2: Option[Int] = None
test2.foreach(println)  ==> prints nothing
test2.exists( _ == 50 )
Boolean = false
test2.exists( _ > 0 )
Boolean = false
test2.forall( _ > 0 )
Boolean = true

Underscore review

def isBig(num: Int) = num >= 100
val collection = Vector(1000, 50, -5, 200, 99)
collection.filterNot(isBig)
=> Vector(50, -5, 99)
collection.filterNot( e => isBig(e) )
=> Vector(50, -5, 99)
collection.filterNot( isBig(_) )
=> Vector(50, -5, 99)

collection.filterNot( e => !isBig(e) )
=> Vector(1000, 200)
collection.filterNot( !isBig(_) )
=> Vector(1000, 200)

collection.filterNot( !isBig )
=> ERROR!!!
In above case, !isBig is not considered unlike isBig.

Key – Value pair

"koira" -> "dog"
(String, String) = (koira, dog)
234513 -> "Teemu Suomi"
(Int, String) = (234513, Teemu Suomi)

Read files

import scala.io.Source
val file = Source.fromFile("text.txt")

try{
  println(file.mkString)
} finally {
  file.close()
} 

file.next() => moves to the next char

If you want to read line by line:
val lineByLine = file.getLines()
println(lineByLine.next())

Read file and print line by line

val file = Source.fromFile("test.txt")
try {
  var linenum = 1
  for(line <- file.getLines()) {
    println(linenum + ":" + line)
    linenum += 1
  }
} finally {
  file.close()
}

How to read a file


val source = fromURL(this.getClass.getResource(filename), &quot;UTF-8&quot;)
try {
source.getLines mkString &quot;\n&quot;  // Make the file as a string seperated by \n. So it will print as it is shown with &quot;enters&quot;
} finally {
source.close()
} 

Write to a file

import java.io.PrintWriter

val fileName = "some.txt"
val file = new PrintWrier(fileName)
try {
  file.println("Hi!")
} finally {
  file.close()
}

groupBy example with Map

class Movie(val name: String,
 val year: Int,
 val position: Int,
 val rating: Double,
 val directors: Vector[String]) {

 override def toString = this.name

}

val movieFile = new IMDBListFile("imdb_top_250_jan_2013.txt")
val allMovies = movieFile.movies
val allDirectors = allMovies.flatMap( _.directors )

val groupedByDirector = allDirectors.groupBy( dir => dir )
groupedByDirector: Map[String,Vector[String]] = Map(Paul Thomas Anderson -> Vector(Paul Thomas Anderson),
Andrey Tarkovskiy -> Vector(Andrey Tarkovskiy), Peter Weir -> Vector(Peter Weir), Wolfgang Petersen ->
Vector(Wolfgang Petersen), Giuseppe Tornatore -> Vector(Giuseppe Tornatore), Robert Rossen ->
Vector(Robert Rossen), Dean DeBlois -> Vector(Dean DeBlois), Charles Chaplin ->
Vector(Charles Chaplin, Charles Chaplin, Charles Chaplin, Charles Chaplin, Charles Chaplin),
Ridley Scott -> Vector(Ridley Scott, Ridley Scott, Ridley Scott), Sean Penn -> Vector(Sean Penn), ...

val countsForEachDirector = groupedByDirector.mapValues( _.size )
countsForEachDirector: Map[String,Int] = Map(Paul Thomas Anderson -> 1, Andrey Tarkovskiy -> 1, Peter
Weir -> 1, Wolfgang Petersen -> 1, Giuseppe Tornatore -> 1, Robert Rossen -> 1, Dean DeBlois -> 1,
Charles Chaplin -> 5, Ridley Scott -> 3, Sean Penn -> 1, Ben Affleck -> 1, Danny Boyle -> 2, ...

countsForEachDirector.foreach(println)
(Paul Thomas Anderson,1)
(Andrey Tarkovskiy,1)
(Peter Weir,1)
(Wolfgang Petersen,1)
(Giuseppe Tornatore,1)
(Robert Rossen,1)
(Dean DeBlois,1)
(Charles Chaplin,5)
(Ridley Scott,3)
(Sean Penn,1)
(Ben Affleck,1)
(Danny Boyle,2)
...

Continue…..


					
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: