Skip to content

Instantly share code, notes, and snippets.

@nobitagit
Last active May 11, 2017 21:00
Show Gist options
  • Save nobitagit/dd3668ba727288aff63fbc6cd2fa6471 to your computer and use it in GitHub Desktop.
Save nobitagit/dd3668ba727288aff63fbc6cd2fa6471 to your computer and use it in GitHub Desktop.
// ARRAYS
// Arrays are immutable fixed length collections
// ArrayBuffers have to be imported and are mutable dynamic length collections
import scala.collection.mutable.ArrayBuffer
val arrB = new ArrayBuffer[Int]
// Add an element
arrB += 1
// Add more elements in one go
arrB += (2,3,4,5)
// concat another Array
arrB ++= Array(6,7,8)
// remove the last 4 elements
arrB.trimEnd(4)
// insert items
arrB.insert(1, 4, 5, 7) // (insert after the 1st index the list of int 4,5,7)
// Array iteration
for (x <- 0 until arrB.length) println(x)
// x will be the index in this case
// note: until means range "NOT INCLUDING" the provided argument.
// Its is actually a function in the form of 0.until(10)
// Also accepts a second argument which is the step
20.until(10, -2)
// which is also:
20 until 10 by -2
// A shorter method is
for (e <- arrB) println(e)
// which is the same as
for (x <- 0 until arrB.length) println(arrB(x))
// Array transformation
for (elem <- arrB) yield 2 * elem
// returns a new Array or ArrayBuffer, depending on the type of the input
// To perform on condition add a GUARD
for (elem <- arrB if elem % 2 == 0) yield 2 * elem
// Array has methods that can be used in place of "for..yeld" blocks
// if that is too imperative for our taste
arrB.filter(_ % 2 == 0).map(_ * 2)
// computes the same thing as above in a more declarative way
// Multidimensional arrays
val matrix = Array.ofDim[Double](3,4)
// An array of Doubles of 3 rows and 4 columns, initialised with all 0.0
[
[0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0]
]
// 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.
import scala.collection.mutable.ArrayBuffer
val arr = Array(1,2,-4,-7,3,2,-4,0)
val arrBuff = new ArrayBuffer[Int]
arrBuff ++= (for (x <- arr if x > 0) yield x)
arrBuff ++= (for (x <- arr if x <= 0) yield x)
arrBuff.toArray // -> Array[Int] = Array(1, 2, 3, 2, -4, -7, -4, 0)
// Sort this array
// DESC
arrBuff.sortWith(_ > _)
// ASC
arrBuff.sortWith(_ < _)
// 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.
val tzs = java.util.TimeZone.getAvailableIDs
tzs
.filter(_.startsWith("America/"))
.map(_.stripPrefix("America/"))
.sortWith(_ < _)
// MAPS
// - Immutable or mutable
// - They are collections of pairs
// A pair
("John", 35)
// A map
Map("John" -> 35)
// A map with multiple pairs
Map("John" -> 35, "Lisa", -> 28)
val myMap = Map("John" -> 35)
// myMap: scala.collection.immutable.Map[String,Int] = Map(John -> 35)
val myMapMutable = scala.collection.mutable.Map("John" -> 35)
// myMapMutable: scala.collection.mutable.Map[String,Int] = Map(John -> 35)
// Immutable maps can be extended by concatenation and reassigning to a new var
val newMap = myMap + ("Thais" -> 41)
// newMap: scala.collection.immutable.Map[String,Int] = Map(john -> 35, Thais -> 41)
// If instead of using a "val" we would have used a "var" when assigning myMap
// the first time we could have just reassigned newMap back to it
myMap = myMap + ("Thais" -> 41)
// Remove an item
myMap = myMap - "Thais"
// Mutate a mutable Map
myMapMutable("Glenn") = 29
myMapMutable += ("Niahm" -> 19, "Cole" -> 31)
// Access a map
myMap("John")
myMap.contains("John")
// Safe getter with fallback to avoid an exception
myMap.getOrElse("John", 0)
// Looping over a Map
for ((k, v) <- myMap) ...
// Get only keys or values
myMap.keySet
myMap.values
// TUPLES
var myTpl = ("Cabbage", 2.99, 4)
// myTpl: (String, Double, Int) = (Cabbage,2.99,4)
// Class[_ <: (String, Double, Int)] = class scala.Tuple3
myTpl._1 // "Cabbage"
myTpl._2 // 2.99
// Note that this method is NOT zero based
// # Destructuring via pattern matching.
// Note that _ is for values we don't need (skipping it throws an error)
val (extract1, extract2, _) = myTpl
// extract1: String = Cabbage
// extract2: Double = 2.99
// Some use cases for tuples
val names = Array("John", "Linda", "Fran")
val ages = Array(32,24,25)
val people = names.zip(ages)
// people is now a tuple, we can covert to Map if needed
names.zip(ages).toMap
// Loope over results
for ((n, a) <- people) ...
// CLASSES
//
// Classes can have nested classes
import scala.collection.mutable.ArrayBuffer
class Department {
// Item will be a nested class belonging to that particular
// instance of the Department class
class Item(val name: String = "Unnamed Item") {
val relatedItems = new ArrayBuffer[Item]
}
private var items = new ArrayBuffer[Item]
def addItem(name: String) = {
val item = new Item(name)
items += item
item
}
}
val phones = new Department
val laptops = new Department
val iphone = phones.addItem("iPhone")
val nokia = phones.addItem("Nokia")
iphone.relatedItems += nokia // it works
val surface = laptops.addItem("Surface")
iphone.relatedItems += surface // (error: type mismatch;) because it does not belong to the same nested class
// If instead we want to be able to cross reference across parent classes we can use a
// COMPANION OBJECT
// (use :paste mode in REPL if testing this snippet)
object Department {
class Item(val name: String = "Unnamed Item") {
val relatedItems = new ArrayBuffer[Item]
}
}
class Department {
private var items = new ArrayBuffer[Department.Item]
def addItem(name: String) = {
val item = new Department.Item(name)
items += item
item
}
}
val bookstore = new Department
val recordstore = new Department
val book1 = bookstore.addItem("Mick Jagger: biography")
val book2 = bookstore.addItem("The history of Rock")
val record1 = recordstore.addItem("Sticky Fingers")
book1.relatedItems += book2
book2.relatedItems += record1 // it works
// Improve the Counter class in Section 5.1, “Simple Classes and Parameterless Methods,”
// on page 49 so that it doesn’t turn negative at Int.MaxValue.
class Counter {
private var value = BigInt(0)
def increment() {
value += 1
}
def setToMaxIntLimit() {
value = Int.MaxValue
}
def current = value
}
// Write a class BankAccount with methods deposit and withdraw, and a read-only property balance.
class BankAccount {
var _balance = 0
def deposit(amount: Int) {
_balance += amount
}
def withdraw(amount: Int) {
_balance -= amount
}
def balance = _balance
}
// 3. Write a class Time with read-only properties hours and minutes and a method
// before(other: Time): Boolean that checks whether this time comes before the
// other. A Time object should be constructed as new Time(hrs, min), where hrs is in
// military time format (between 0 and 23).
class Time(val hrs: Int, val min: Int) {
require(hrs >= 0 && hrs < 24)
require(min >= 0 && min < 60)
def before(other: Time) : Boolean = {
(hrs < other.hrs || (hrs == other.hrs && min < other.min))
}
}
// 4. Reimplement the Time class from the preceding exercise so that the internal representation
// is the number of minutes since midnight (between 0 and 24 * 60 - 1).
// Do not change the public interface. That is, client code should be unaffected by your change.
class Time(val hrs: Int, val min: Int) {
require(hrs >= 0 && hrs < 24)
require(min >= 0 && min < 60)
_time = hrs * 60 + min
def time = _time
def before(other: Time) : Boolean = {
(_time < other.time)
}
}
// 5. Make a class Student with read-write JavaBeans properties name (of type String) and
// id (of type Long). What methods are generated? (Use javap to check.)
// Can you call the JavaBeans getters and setters in Scala Should you?”
import scala.beans._
class Person(@BeanProperty var firstName: String, @BeanProperty var id: Long) {}
// See: http://alvinalexander.com/scala/how-to-disassemble-decompile-scala-source-code-javap-scalac-jad
// Save to a file, say test.scala then compile:
// > scalac test.scala
// then run:
// javap Person
/*
public class Person {
public java.lang.String firstName();
public void firstName_$eq(java.lang.String);
public long id();
public void id_$eq(long);
public java.lang.String getFirstName();
public void setFirstName(java.lang.String);
public long getId();
public void setId(long);
public Person(java.lang.String, long);
}
*/
// So we can make:
val john = new Person("John", 123)
john.getFirstName
// > John
john.setFirstName("Louis")
john.getFirstName
// > Louis
// 6. In the Person class of Section 5.1, “Simple Classes and Parameterless Methods,” on page 49,
// provide a primary constructor that turns negative ages to 0.
class Person(val age: Int) {
if (age < 0) age = 0
}
// 7. Write a class Person with a primary constructor that accepts a string containing
// a first name, a space, and a last name, such as new Person("Fred Smith"). Supply
// read-only properties firstName and lastName. Should the primary constructor
// parameter be a var, a val, or a plain parameter? Why?
class Person1(val fullName: String) {
val split = fullName.split(" ")
val firstName : String = split(0);
val lastName : String = split(1);
}
// Actually I did wrong, it should just be class Person(fullName: String)
// since no method uses it. This is how it should be done in this case.
class Person2(fullName: String) {
val split = fullName.split(" ")
val firstName : String = split(0);
val lastName : String = split(1);
}
// To test this out, try instatiating new Person1("John Smith")
// and then access person.fullName. This will work, while
// the same is not true for an insatnce of Person2, which will throw.
// This concept is explained in 5.7 The Primary Contructor
// 8. Make a class Car with read-only properties for manufacturer, model name,
// and model year, and a read-write property for the license plate. Supply four
// constructors. All require the manufacturer and model name. Optionally,
// model year and license plate can also be specified in the constructor. If not,
// the model year is set to -1 and the license plate to the empty string. Which
// constructor are you choosing as the primary constructor? Why?
// Let's recap a few basics. Defining Car this way
class Car(var manufacturer: String) {}
// Scala sets up a private field called manufacturer, with a getter and a setter method for it
// We can in fact do:
var car = new Car("Fiat")
car.manufacturer
// > "Fiat"
car.manufacturer = "Volvo" //
// > "Volvo"
// If we save the class definition to a file called Car.class
// and run `scalac car.scala javap -private Car` we'll See
//> javap -private Car.class
//> Compiled from "car.scala"
public class Car {
private java.lang.String manufacturer; // <= private value
public java.lang.String manufacturer(); // <= getter
public void manufacturer_$eq(java.lang.String); // <= setter
public Car(java.lang.String); // <= constructor
}
// NOTE: if the field is a val only a getter is set up, though
class Car(val manufacturer: String) {}
// equates
public class Car {
private final java.lang.String manufacturer;
public java.lang.String manufacturer();
public Car(java.lang.String);
}
// ## Primary Constructor (P.C.) and Auxiliary constuctors (A.C.)
class Song {
private var title = "" // <= PC
private var length = 0 // <=//
def this(name: String) { // <= A.C. #1
this() // <= call the primary constructor
this.title = title
}
def this(title: String, length: Int) { // <= A.C. #2
this(name) // <= call the A.C # 1
this.length = length
}
}
// 10. Consider the class:
class Employee(val name: String, var salary Double) {
def this() { this("John Public", 0.0) }
}
// Rewrite it to use explicit fields and a default primary constructor.
// Which form do you prefer? Why?
class Employee(val name: String = "John Public", val salary: Double = 0.0) {}
// Write a function that takes a character and returns the next character in the alphabet
def nextChar(char: Char) : Char = {
(char + 1).toChar
}
// Set up a map of prices for a number of gizmos that you covet.
// Then produce a second map with the same keys and the prices at a 10 percent discount.
var gizmos = Map("S7" -> 510.00, "Glasses" -> 300.00, "RayBan" -> 320.00)
for ((k, v) <- gizmos) yield (k, v - (v / 10))
// scala.collection.immutable.Map[String,Double] = Map(S7 -> 459.0, Glasses -> 270.0, RayBan -> 288.0)
// or...
gizmos.map(t => (t._1, t._2 - (t._2 / 10)))
// scala.collection.immutable.Map[String,Double] = Map(S7 -> 459.0, Glasses -> 270.0, RayBan -> 288.0)
// Ch4
// Write a program that reads words from a file. Use a mutable map to count
// how often each word appears.
val in = new java.util.Scanner(new java.io.File("myfile.txt"))
var hashMap = scala.collection.mutable.Map[String, Int]()
while (in.hasNext()) {
val w = in.next()
hashMap(w) = hashMap.getOrElse(w, 0) + 1
}
for ((k, v) <- hashMap) println(k, v)
// Repeat the preceding exercise with an immutable map.
val in = new java.util.Scanner(new java.io.File("myfile.txt"))
var hashMap = Map[String, Int]()
while (in.hasNext()) {
val w = in.next()
val occ = hashMap.getOrElse(w, 0) + 1
hashMap = hashMap + (w -> occ)
}
for ((k, v) <- hashMap) println(k, v)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment