Scala Interview Questions with Answers
Most Asked Scala Interview Questions for Software Engineer Roles
Introduction
Scala is a high‑performance language that seamlessly blends object‑oriented and functional programming. This page collects the most frequently asked Scala interview questions – from basic syntax and collections to advanced type system, implicits, concurrency, and integration with the JVM ecosystem – essential for any backend, big data, or functional programmer.
Why Scala?
- Combines OOP and functional programming on the JVM
- Powerful type system with inference and generics
- Immutable data structures and functional transformations
- Industry adoption in big data (Spark, Kafka, Akka)
- Full interoperability with Java libraries and tooling
- Expressive syntax that reduces boilerplate
Most Asked Scala Interview Questions
Scala is a modern multi-paradigm programming language designed to express common programming patterns in a concise, elegant, and type-safe way.
- Functional: Functions are first-class citizens
- Object-oriented: Every value is an object
- Type-safe: Strong static type system
- JVM compatible: Runs on Java Virtual Machine
- Concurrent: Built-in support for concurrency
// Hello World in Scala
object HelloWorld {
def main(args: Array[String]): Unit = {
println("Hello, World!")
}
}
// Or using App trait
object HelloWorld extends App {
println("Hello, World!")
}Variables in Scala are declared using val for immutable values and var for mutable variables.
- Immutable:
val x = 10 - Mutable:
var y = 20 - Type inference: Types are inferred automatically
- Type annotation:
val x: Int = 10 - Lazy:
lazy val z = expensive()
// Variables in Scala
// Immutable variable (val)
val x: Int = 10
val y: Double = 3.14
val name: String = "Scala"
val isActive: Boolean = true
// Mutable variable (var)
var counter: Int = 0
counter = 1
// Type inference
val a = 10 // Int
val b = 3.14 // Double
val c = "Scala" // String
val d = true // Boolean
println(x)
println(y)
println(name)
println(isActive)Scala has a rich type system with both value types and reference types, all unified under the Any type.
- Numeric:
Int,Long,Double,Float - Boolean:
Boolean - String:
String - Char:
Char - Unit:
Unit(void) - Any: Top type
- Nothing: Bottom type
- Option:
Option[T] - Tuple:
(Int, String) - List:
List[Int]
// Data Types in Scala
// Integer types
val a: Int = 10
val b: Long = 100L
val c: Short = 127
val d: Byte = 127
// Floating point
val e: Double = 3.14
val f: Float = 2.5f
// String
val g: String = "Hello Scala"
// Boolean
val h: Boolean = true
val i: Boolean = false
// Char
val j: Char = 'A'
// Unit (void)
val k: Unit = ()
// Any (top type)
val l: Any = 42
val m: Any = "Hello"
// Nothing (bottom type)
// val n: Nothing = ???
// Null
val o: String = null
// Option
val p: Option[Int] = Some(42)
val q: Option[Int] = None
// Tuple
val r: (Int, String, Double) = (1, "hello", 3.14)
// List
val s: List[Int] = List(1, 2, 3, 4, 5)
// Map
val t: Map[String, Int] = Map("Scala" -> 3, "Java" -> 8)
println(a.getClass)
println(e.getClass)Functions in Scala are defined using the def keyword, with support for default parameters, type inference, and higher-order functions.
- Function declaration:
def add(a: Int, b: Int): Int = a + b - Default parameters:
def greet(name: String = "Guest") - Anonymous functions:
(x: Int) => x * 2 - Currying:
def add(a: Int)(b: Int) = a + b - Variable arguments:
def sum(numbers: Int*) = numbers.sum
// Functions in Scala
// Function declaration
def add(a: Int, b: Int): Int = {
return a + b
}
// One-line function
def subtract(a: Int, b: Int): Int = a - b
// Function with default parameters
def greet(name: String = "Guest"): String = {
s"Hello, $name!"
}
// Anonymous function (lambda)
val square: Int => Int = (x: Int) => x * x
val double: Int => Int = _ * 2
// Higher-order function
def applyTwice(f: Int => Int, x: Int): Int = f(f(x))
// Function with multiple parameter lists (currying)
def addCurried(a: Int)(b: Int): Int = a + b
// Function with variable arguments
def sumAll(numbers: Int*): Int = numbers.sum
// Function with named arguments
def createPerson(name: String, age: Int = 0, city: String = "Unknown"): String = {
s"$name ($age) from $city"
}
// Partial function
val partialAdd: Int => Int = addCurried(5)
// Usage
println(add(5, 3))
println(subtract(10, 4))
println(greet("Alice"))
println(square(4))
println(applyTwice(_ * 2, 5))
println(addCurried(5)(3))
println(sumAll(1, 2, 3, 4, 5))
println(createPerson("Alice", age = 25, city = "NYC"))Lists are immutable, homogeneous collections in Scala. They are constructed using List and :: (cons) operators.
- Creation:
List(1, 2, 3, 4, 5) - Cons:
0 :: List(1, 2, 3) - Concatenation:
List(1, 2) ++ List(3, 4) - Functions:
map,filter,reduce - Pattern matching:
case head :: tail => ...
// Lists in Scala
val arr: List[Int] = List(1, 2, 3, 4, 5)
// Map - transform each element
val doubled: List[Int] = arr.map(_ * 2)
println(doubled)
// Filter - select elements
val evens: List[Int] = arr.filter(_ % 2 == 0)
println(evens)
// Reduce - aggregate
val sum: Int = arr.reduce(_ + _)
println(sum)
// Fold - aggregate with initial value
val sumFold: Int = arr.foldLeft(0)(_ + _)
// List comprehension (for-comprehension)
val squares: List[Int] = for (x <- 1 to 10) yield x * x
println(squares)
// Push and prepend
val newList: List[Int] = 6 :: arr
println(newList)
val popped: List[Int] = arr.dropRight(1)
println(popped)
// List operations
val a: List[Int] = List(1, 2, 3)
val b: List[Int] = List(4, 5, 6)
val c: List[Int] = a ++ b // Concatenation
println(c)Maps in Scala are immutable key-value pairs, similar to dictionaries. They provide efficient lookup and operations.
- Creation:
Map("name" -> "Alice", "age" -> 25) - Access:
map("name") - Add/Update:
map + ("country" -> "USA") - Keys/Values:
map.keys,map.values - Get with default:
map.getOrElse("key", "default")
// Maps (Dictionaries) in Scala
// Create map
val person: Map[String, Any] = Map(
"name" -> "Alice",
"age" -> 25,
"city" -> "NYC"
)
// Access values
println(person("name"))
println(person.get("age"))
// Get with default
val city: String = person.getOrElse("city", "Unknown")
// Add/update values (immutable)
val updatedPerson: Map[String, Any] = person + ("country" -> "USA")
val updatedAge: Map[String, Any] = updatedPerson + ("age" -> 26)
// Keys and values
println(person.keys)
println(person.values)
// Iterate over map
for ((key, value) <- person) {
println(s"$key: $value")
}
// Delete key
val withoutCountry: Map[String, Any] = updatedPerson - "country"
// Check if key exists
println(person.contains("name"))
// Map comprehension
val squares: Map[Int, Int] = (1 to 5).map(i => i -> (i * i)).toMap
println(squares)Tuples are immutable containers that can hold a fixed number of elements of different types.
- Creation:
(1, "hello", 3.14) - Access:
tuple._1 - Pattern matching:
case (a, b, c) => - Named tuples: Use case classes
- Function return: Multiple values
// Tuples in Scala
// Create tuple
val t: (Int, String, Double, Boolean) = (1, "hello", 3.14, true)
// Access elements
println(t._1)
println(t._2)
// Pattern matching to extract
val (a, b, c, d) = t
println(a, b, c, d)
// Named tuple (using case class)
case class Person(name: String, age: Int, city: String)
val alice: Person = Person("Alice", 25, "NYC")
println(alice.name)
println(alice.age)
// Function returning multiple values
def divide(a: Int, b: Int): (Int, Int) = (a / b, a % b)
val (quotient, remainder) = divide(10, 3)
println(s"Quotient: $quotient, Remainder: $remainder")
// Tuple concatenation
val t1: (Int, Int) = (1, 2)
val t2: (Int, Int) = (3, 4)
val t3: (Int, Int, Int, Int) = (t1._1, t1._2, t2._1, t2._2)
println(t3)Scala provides standard control flow statements including conditionals, loops, and powerful pattern matching.
- If-else:
if (condition) ... else ... - For loops:
for (i <- 1 to 10) { ... } - For comprehensions:
for (x <- list) yield x * 2 - While loops:
while (condition) { ... } - Pattern matching:
value match { case 0 => ... }
// Control Flow in Scala
// If-else statement
val age: Int = 25
val status: String = if (age < 18) "Minor"
else if (age < 65) "Adult"
else "Senior"
println(status)
// For loop
for (i <- 1 to 5) {
println(i)
}
// For loop with collection
val fruits: List[String] = List("apple", "banana", "orange")
for (fruit <- fruits) {
println(fruit)
}
// For comprehension
val doubled: List[Int] = for (i <- 1 to 10) yield i * 2
println(doubled)
// While loop
var i: Int = 1
while (i <= 5) {
println(i)
i += 1
}
// Do-while loop
var j: Int = 1
do {
println(j)
j += 1
} while (j <= 5)
// Break and continue (using breakable)
import scala.util.control.Breaks._
breakable {
for (i <- 1 to 10) {
if (i == 6) break
if (i % 2 == 0) {
// continue - just don't execute rest of loop body
// Scala doesn't have continue, use if guard instead
}
println(i)
}
}
// Pattern matching (powerful control flow)
val number: Int = 2
number match {
case 0 => println("Zero")
case 1 => println("One")
case 2 => println("Two")
case _ => println("Other")
}For-comprehensions in Scala provide a powerful way to work with collections and monads, similar to list comprehensions in other languages.
- For-comprehension:
for (x <- 1 to 10) yield x * x - Filtering:
for (x <- 1 to 20 if x % 2 == 0) yield x - Nested:
for (i <- 1 to 3; j <- 1 to 3) yield (i, j) - Map comprehension:
(1 to 5).map(i => i -> i*i).toMap - Lazy:
LazyList.from(1).map(_ * 2)
// Comprehensions in Scala
// For-comprehension
val squares: List[Int] = for (x <- 1 to 10) yield x * x
println(squares)
// Filter in comprehension
val evens: List[Int] = for {
x <- 1 to 20
if x % 2 == 0
} yield x
println(evens)
// Nested comprehension
val pairs: List[(Int, Int)] = for {
i <- 1 to 3
j <- 1 to 3
} yield (i, j)
println(pairs)
// Map comprehension
val squareMap: Map[Int, Int] = (1 to 5).map(i => (i, i * i)).toMap
println(squareMap)
// Generator expression (lazy)
val lazySquares: LazyList[Int] = LazyList.from(1).map(x => x * x)
println(lazySquares.take(10).toList)
// Conditional comprehension
val results: List[String] = for (x <- 1 to 10) yield {
if (x % 2 == 0) "even" else "odd"
}
println(results)Scala provides rich string manipulation capabilities using Java's String class and additional Scala features.
- Concatenation:
"Hello" + " World" - Interpolation:
s"Welcome to $name" - f-interpolation:
f"Value: 3.14%.2f" - Functions:
length,toUpperCase,replace - Split/Join:
split,mkString
// Strings in Scala
// String creation
val str1: String = "Hello"
val str2: String = "World"
val str3: String = """Multi-line
string"""
// String concatenation
val greeting: String = str1 + " " + str2
println(greeting)
// String interpolation
val name: String = "Scala"
val version: Double = 2.13
println(s"Welcome to $name version $version")
// f-interpolation (formatting)
println(f"Value: 3.14159%.2f")
// String functions
val text: String = "Hello, World!"
println(text.length)
println(text.toUpperCase)
println(text.toLowerCase)
println(text.replace("World", "Scala"))
// Substring
println(text.substring(0, 5))
// Split and join
val words: Array[String] = "Hello World Scala".split(" ")
println(words.mkString(", "))
val joined: String = words.mkString("-")
println(joined)
// String comparison
println("hello" == "hello")
println("hello".compareTo("world") < 0)
// String formatting
println("%.2f".format(3.14159))Packages in Scala organize code into namespaces and provide modularity, similar to Java packages.
- Definition:
package com.example - Nested packages:
package com.example.math - Import:
import com.example.math.MathUtils - Wildcard import:
import com.example.math._ - Renaming:
import com.example.math.{MathUtils => Math}
// Packages and Imports in Scala
// Defining a package
package com.example {
package math {
object MathUtils {
val PI: Double = 3.14159
def add(a: Int, b: Int): Int = a + b
def subtract(a: Int, b: Int): Int = a - b
}
}
}
// Using imported items
import com.example.math.MathUtils
println(MathUtils.PI)
println(MathUtils.add(5, 3))
println(MathUtils.subtract(10, 4))
// Importing multiple items
import com.example.math.MathUtils.{add, subtract, PI}
// Importing everything
import com.example.math.MathUtils._
// Renaming imports
import com.example.math.MathUtils.{add => addNumbers, PI => PiValue}
// Importing with alias
import com.example.math.{MathUtils => Math}
println(Math.add(5, 3))
println(Math.PI)
// Package object
package object utils {
def log(message: String): Unit = println(s"LOG: $message")
}
// Using package object
import utils.log
log("Application started")
// Importing from Java
import java.util.{ArrayList, HashMap}
import java.io.{File, FileWriter}
// Importing from Scala standard library
import scala.collection.mutable.{ArrayBuffer, HashMap => MutableHashMap}Classes in Scala are blueprints for objects, supporting both functional and object-oriented programming paradigms.
- Class definition:
class Person(val name: String, var age: Int) - Case classes:
case class Person(name: String, age: Int) - Singleton objects:
object Person - Abstract classes:
abstract class Animal - Traits:
trait SoundMaker
// Classes and Types in Scala
// Abstract class
abstract class Animal {
val name: String
val age: Int
def makeSound(): String
}
// Case class (immutable)
case class Dog(name: String, age: Int) extends Animal {
def makeSound(): String = "Woof!"
}
// Regular class
class Person(val name: String, var age: Int, val city: String = "Unknown") {
def greet(): String = s"Hello, I'm $name"
def haveBirthday(): Unit = {
age += 1
}
}
// Singleton object (companion)
object Person {
def apply(name: String, age: Int): Person = new Person(name, age)
}
// Case class with additional methods
case class Cat(name: String, age: Int) extends Animal {
def makeSound(): String = "Meow!"
}
// Usage
val dog: Dog = Dog("Rex", 3)
val cat: Cat = Cat("Whiskers", 2)
val person: Person = Person("Alice", 25)
println(dog.makeSound())
println(cat.makeSound())
println(person.greet())
person.haveBirthday()
println(s"Age: ${person.age}")Scala has a powerful, expressive type system that combines object-oriented and functional programming features.
- Type inference:
val x = 42 - Type annotations:
val x: Int = 42 - Generic types:
class Box[A] - Type bounds:
[A <: AnyRef] - Type aliases:
type IntList = List[Int]
// Type System in Scala
// Type declarations
def describe(x: Int): String = s"Integer: $x"
def describe(x: Double): String = s"Double: $x"
def describe(x: String): String = s"String: $x"
// Generic types
class Box[A](val value: A) {
def get: A = value
def map[B](f: A => B): Box[B] = new Box(f(value))
}
// Type parameters
def identity[A](x: A): A = x
// Type bounds
class Container[A <: AnyRef](val value: A)
// Upper bound
def processNumbers[A <: Number](x: A): Double = x.doubleValue()
// Lower bound
def appendToList[A >: String](list: List[A], item: A): List[A] = list :+ item
// Type variance
class Covariant[+A] // Covariant
class Contravariant[-A] // Contravariant
class Invariant[A] // Invariant
// Type aliases
type IntList = List[Int]
type StringMap = Map[String, String]
// Self type
trait Logger { self: AnyRef =>
def log(msg: String): Unit = println(s"LOG: $msg")
}
// Usage
describe(42)
describe(3.14)
describe("Hello")
val box: Box[Int] = new Box(42)
val mapped: Box[String] = box.map(_.toString)
identity(5)
identity("Hello")
// Type checking
val isInt: Boolean = 42.isInstanceOf[Int]
val intValue: Int = 42.asInstanceOf[Int]Scala provides both traditional try-catch blocks and functional error handling with Try, Either, and Option.
- Try-catch:
try { ... } catch { case e: Exception => ... } - Try:
Try(expression) - Either:
Either[String, Int] - Option:
Some(value)orNone - Finally:
try { ... } finally { ... }
// Exception Handling in Scala
// Try-catch block
import scala.util.{Try, Success, Failure}
try {
// Code that might error
val result = 10 / 0
println(result)
} catch {
case e: ArithmeticException =>
println(s"Arithmetic error: ${e.getMessage}")
case e: Exception =>
println(s"Other error: ${e.getMessage}")
} finally {
println("Cleanup performed")
}
// Specific error handling
try {
val arr = Array(1, 2, 3)
println(arr(10))
} catch {
case e: ArrayIndexOutOfBoundsException =>
println("Index out of bounds!")
case e: Exception =>
println(s"Other error: ${e.getMessage}")
}
// Using Try (functional error handling)
def divide(a: Int, b: Int): Try[Int] = Try(a / b)
val result1: Try[Int] = divide(10, 2)
val result2: Try[Int] = divide(10, 0)
result1 match {
case Success(value) => println(s"Result: $value")
case Failure(e) => println(s"Error: ${e.getMessage}")
}
result2 match {
case Success(value) => println(s"Result: $value")
case Failure(e) => println(s"Error: ${e.getMessage}")
}
// Using Either for error handling
def safeDivide(a: Int, b: Int): Either[String, Int] = {
if (b == 0) Left("Cannot divide by zero")
else Right(a / b)
}
safeDivide(10, 2) match {
case Right(value) => println(s"Result: $value")
case Left(error) => println(s"Error: $error")
}
// Throwing exceptions
def validateInput(x: Int): Int = {
if (x < 0) throw new IllegalArgumentException("Input must be non-negative")
x
}
// Custom exception
class MyException(message: String) extends Exception(message)
// Using Option for nullable values
def toInt(s: String): Option[Int] = {
try {
Some(s.toInt)
} catch {
case _: NumberFormatException => None
}
}Scala uses Java's I/O libraries, with additional convenience methods from Scala's standard library.
- Read:
Source.fromFile("file.txt").mkString - Line by line:
Source.fromFile("file.txt").getLines() - Write:
new PrintWriter("file.txt").write("content") - Append:
new PrintWriter(new FileWriter("file.txt", true)) - CSV: Manual parsing or libraries
// File I/O in Scala
import scala.io.Source
import java.io.{PrintWriter, File}
// Reading files
try {
val source = Source.fromFile("example.txt")
val content = source.mkString
println(content)
source.close()
} catch {
case e: Exception => println(s"File not found: ${e.getMessage}")
}
// Reading line by line
try {
val source = Source.fromFile("data.txt")
for (line <- source.getLines()) {
println(line)
}
source.close()
} catch {
case e: Exception => println(s"Error reading file: ${e.getMessage}")
}
// Writing files
val writer = new PrintWriter(new File("output.txt"))
writer.write("Hello, World!\n")
writer.write("This is line 2\n")
writer.close()
// Appending to files
val appendWriter = new PrintWriter(new FileWriter("output.txt", true))
appendWriter.write("Appended line\n")
appendWriter.close()
// Reading CSV (using Scala's standard library)
val csvSource = Source.fromFile("data.csv")
val rows = csvSource.getLines().map(_.split(",")).toList
rows.foreach(row => println(row.mkString(", ")))
csvSource.close()
// Writing CSV
val data = List(
List("Name", "Age", "City"),
List("Alice", "25", "NYC"),
List("Bob", "30", "LA")
)
val csvWriter = new PrintWriter(new File("output.csv"))
data.foreach(row => csvWriter.println(row.mkString(",")))
csvWriter.close()
// Using Scala's better-files (requires library)
// import better.files._
// val content = file"example.txt".contentAsString
// file"output.txt".write("Hello, World!")Scala uses sbt (Simple Build Tool) as the primary build tool with Maven Central for package management.
- sbt:
build.sbtfile - Library dependencies:
libraryDependencies += "org.typelevel" %% "cats-core" % "2.9.0" - Add packages:
sbt add package-name - Import:
import package.name - Ammonite:
import $ivy.`org.typelevel::cats-core:2.9.0`
// Packages and Build Tools in Scala
// build.sbt (Simple Build Tool)
/*
name := "my-project"
version := "1.0"
scalaVersion := "2.13.10"
libraryDependencies ++= Seq(
"org.typelevel" %% "cats-core" % "2.9.0",
"org.scalatest" %% "scalatest" % "3.2.15" % Test
)
*/
// Using packages in code
import cats._
import cats.implicits._
// Using Akka
// import akka.actor._
// Using Play Framework
// import play.api.libs.json._
// Using Spark
// import org.apache.spark.SparkContext
// Using Slick for database
// import slick.jdbc.PostgresProfile.api._
// Using ScalaTest for testing
/*
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
class MySpec extends AnyFlatSpec with Matchers {
"A calculator" should "add two numbers" in {
assert(2 + 2 == 4)
}
}
*/
// Using Ammonite (REPL)
// $ ammonite
// @ import $ivy.`org.typelevel::cats-core:2.9.0`
// Using sbt commands
// sbt compile
// sbt run
// sbt test
// sbt assembly (for fat JAR)
// Using Mill as alternative build tool
// build.mill
/*
import mill._, scalalib._
object myproject extends ScalaModule {
def scalaVersion = "2.13.10"
}
*/Scala supports plotting through libraries like Plotly-Scala, JFreeChart, and Vegas.
- Plotly-Scala:
Scatter(x, y, mode = ScatterMode.Lines) - Vegas:
Vegas("Chart").mark(Bar).show - JFreeChart: Java library integration
- Wisp: Plotly for Scala.js
- Apache Commons Math: Data generation
// Plotting in Scala
// Using Plotly-Scala
// libraryDependencies += "org.plotly-scala" %% "plotly-render" % "0.8.4"
/*
import plotly._
import plotly.element._
import plotly.layout._
val x = Seq(1, 2, 3, 4, 5)
val y = Seq(1, 4, 9, 16, 25)
val trace = Scatter(x, y, mode = ScatterMode.LinesMarkers)
val layout = Layout(title = "Square Function")
Plotly.plot("plot.html", trace, layout)
*/
// Using JFreeChart
// import org.jfree.chart.ChartFactory
// import org.jfree.chart.plot.PlotOrientation
// import org.jfree.data.xy.XYSeriesCollection
// import org.jfree.data.xy.XYSeries
// Using Vegas (Vega-Lite wrapper)
// libraryDependencies += "org.vegas-viz" %% "vegas" % "0.3.11"
/*
import vegas._
val data = Seq(
("A", 1), ("B", 2), ("C", 3), ("D", 4), ("E", 5)
)
Vegas("Bar Chart")
.withData(data)
.mark(Bar)
.encodeX("_1", nom)
.encodeY("_2", quant)
.show
*/
// Using Wisp (plotly for Scala.js)
// libraryDependencies += "com.quantifind" %% "wisp" % "0.0.4"
// Using Scala-Plot (simple plotting)
// libraryDependencies += "com.github.tototoshi" %% "scala-plot" % "0.2.0"
// Using Apache Commons Math for data generation
// libraryDependencies += "org.apache.commons" % "commons-math3" % "3.6.1"Scala provides both immutable and mutable data structures in its standard library.
- Immutable:
List,Vector,Set,Map - Mutable:
ArrayBuffer,mutable.ListBuffer - Stack:
mutable.ArrayStack - Queue:
mutable.Queue - Array:
Array(Java compatible)
// Data Structures in Scala
// Immutable collections
val list = List(1, 2, 3, 4, 5)
val vector = Vector(1, 2, 3, 4, 5)
val set = Set(1, 2, 3, 4, 5)
val map = Map("a" -> 1, "b" -> 2, "c" -> 3)
// Mutable collections
import scala.collection.mutable
val mutableList = mutable.ListBuffer(1, 2, 3)
mutableList += 4
val mutableSet = mutable.Set(1, 2, 3)
mutableSet += 4
val mutableMap = mutable.Map("a" -> 1, "b" -> 2)
mutableMap("c") = 3
// Stack (using ListBuffer or ArrayStack)
val stack = mutable.ArrayStack[Int]()
stack.push(1)
stack.push(2)
stack.push(3)
val popped = stack.pop()
// Queue
val queue = mutable.Queue[Int]()
queue.enqueue(1)
queue.enqueue(2)
queue.enqueue(3)
val dequeued = queue.dequeue()
// Array
val array = Array(1, 2, 3, 4, 5)
array(0) = 10
// ArrayBuffer
val arrayBuffer = mutable.ArrayBuffer(1, 2, 3)
arrayBuffer += 4
arrayBuffer.append(5)
// Map operations
val updatedMap = map + ("d" -> 4)
val withoutA = map - "a"
// Set operations
val union = set ++ Set(6, 7, 8)
val intersect = set & Set(2, 3, 4)
// List operations
val concatenated = list ++ List(6, 7, 8)
val head = list.head
val tail = list.tail
val length = list.length
// Using Stream (lazy list)
val stream = LazyList.continually(1)
val firstTen = stream.take(10).toListScala provides statistical functions through its standard library and scientific libraries like Breeze.
- Mean:
data.sum / data.length - Median:
sorted(data.length / 2) - Standard deviation: Custom calculation
- Correlation: Manual calculation
- Breeze:
mean(vec),variance(vec)
// Statistics in Scala
import scala.math.{sqrt, pow}
// Basic statistics
def mean(data: Seq[Double]): Double = {
if (data.isEmpty) 0.0 else data.sum / data.length
}
def median(data: Seq[Double]): Double = {
val sorted = data.sorted
val length = sorted.length
if (length % 2 == 1) sorted(length / 2)
else (sorted(length / 2 - 1) + sorted(length / 2)) / 2.0
}
def variance(data: Seq[Double]): Double = {
val m = mean(data)
data.map(x => pow(x - m, 2)).sum / data.length
}
def stdDev(data: Seq[Double]): Double = sqrt(variance(data))
def correlation(x: Seq[Double], y: Seq[Double]): Double = {
val n = x.length
val meanX = mean(x)
val meanY = mean(y)
val sumXY = x.zip(y).map { case (xi, yi) => (xi - meanX) * (yi - meanY) }.sum
val sumX2 = x.map(xi => pow(xi - meanX, 2)).sum
val sumY2 = y.map(yi => pow(yi - meanY, 2)).sum
sumXY / sqrt(sumX2 * sumY2)
}
def quantile(data: Seq[Double], q: Double): Double = {
val sorted = data.sorted
val n = sorted.length
val pos = (n - 1) * q
val base = pos.floor.toInt
val frac = pos - base
if (frac == 0) sorted(base)
else sorted(base) + frac * (sorted(base + 1) - sorted(base))
}
// Usage
val data = (1 to 10).map(_.toDouble)
println(s"Mean: ${mean(data)}")
println(s"Median: ${median(data)}")
println(s"Std Dev: ${stdDev(data)}")
println(s"Variance: ${variance(data)}")
val x = (1 to 100).map(_.toDouble)
val y = x.map(xi => 2 * xi + scala.util.Random.nextDouble() * 20 - 10)
println(s"Correlation: ${correlation(x, y)}")
println(s"Q25: ${quantile(data, 0.25)}")
println(s"Q75: ${quantile(data, 0.75)}")
// Using Breeze (scientific library)
// libraryDependencies += "org.scalanlp" %% "breeze" % "2.0.0"
/*
import breeze.linalg._
import breeze.stats._
val vec = DenseVector(1.0, 2.0, 3.0, 4.0, 5.0)
println(mean(vec))
println(variance(vec))
println(stddev(vec))
*/Scala provides linear algebra operations through custom implementations or the Breeze scientific library.
- Matrix multiplication:
matMul(A, B) - Transpose:
transpose(matrix) - Determinant:
determinant(matrix) - Breeze:
DenseMatrix,DenseVector - Operations:
a * b,a.t,det(a)
// Linear Algebra in Scala
// Matrix operations
def matMul(A: Array[Array[Double]], B: Array[Array[Double]]): Array[Array[Double]] = {
val rows = A.length
val cols = B(0).length
val inner = B.length
val result = Array.ofDim[Double](rows, cols)
for (i <- 0 until rows; j <- 0 until cols; k <- 0 until inner) {
result(i)(j) += A(i)(k) * B(k)(j)
}
result
}
def transpose(matrix: Array[Array[Double]]): Array[Array[Double]] = {
val rows = matrix.length
val cols = matrix(0).length
val result = Array.ofDim[Double](cols, rows)
for (i <- 0 until rows; j <- 0 until cols) {
result(j)(i) = matrix(i)(j)
}
result
}
def determinant(matrix: Array[Array[Double]]): Double = {
val n = matrix.length
if (n == 1) return matrix(0)(0)
if (n == 2) return matrix(0)(0) * matrix(1)(1) - matrix(0)(1) * matrix(1)(0)
var det = 0.0
for (j <- 0 until n) {
val subMatrix = Array.ofDim[Double](n - 1, n - 1)
for (i <- 1 until n; k <- 0 until n if k != j) {
subMatrix(i - 1)(k - (if (k > j) 1 else 0)) = matrix(i)(k)
}
det += (if (j % 2 == 0) 1 else -1) * matrix(0)(j) * determinant(subMatrix)
}
det
}
// Vector operations
def vectorAdd(a: Array[Double], b: Array[Double]): Array[Double] = {
a.zip(b).map { case (x, y) => x + y }
}
def dotProduct(a: Array[Double], b: Array[Double]): Double = {
a.zip(b).map { case (x, y) => x * y }.sum
}
def norm(a: Array[Double]): Double = {
sqrt(a.map(x => x * x).sum)
}
// Using Breeze
/*
import breeze.linalg._
val A = DenseMatrix((1.0, 2.0, 3.0), (4.0, 5.0, 6.0), (7.0, 8.0, 10.0))
val B = DenseMatrix((1.0), (2.0), (3.0))
val product = A * B
val transposed = A.t
val det = det(A)
val inv = inv(A)
*/
// Usage
val A = Array(
Array(1.0, 2.0, 3.0),
Array(4.0, 5.0, 6.0),
Array(7.0, 8.0, 10.0)
)
val B = Array(Array(1.0), Array(2.0), Array(3.0))
val product = matMul(A, B)
val transposed = transpose(A)
val det = determinant(A)
val v1 = Array(1.0, 2.0, 3.0)
val v2 = Array(4.0, 5.0, 6.0)
println(s"Matrix product: ${product.map(_.mkString(", ")).mkString("; ")}")
println(s"Transpose: ${transposed.map(_.mkString(", ")).mkString("; ")}")
println(s"Determinant: $det")
println(s"Dot product: ${dotProduct(v1, v2)}")
println(s"Norm: ${norm(v1)}")Scala uses Java's time API (java.time) for comprehensive date and time handling.
- Current:
LocalDateTime.now() - Create:
LocalDate.of(2024, 1, 1) - Arithmetic:
date.plusDays(10) - Difference:
Period.between(date1, date2) - Formatting:
DateTimeFormatter
// Dates and Time in Scala
import java.time.{LocalDate, LocalDateTime, LocalTime, ZoneId, Period, Duration}
import java.time.format.DateTimeFormatter
// Current date and time
val now = LocalDateTime.now()
println(now)
// Date creation
val date1 = LocalDate.of(2024, 1, 1)
val date2 = LocalDateTime.of(2024, 1, 1, 12, 0, 0)
println(date1)
println(date2)
// Date arithmetic
println(date1.plusDays(10))
println(date1.plusMonths(2))
println(date2.plusHours(3))
// Date difference
val diff = Period.between(date1, LocalDate.now())
println(s"${diff.getYears} years, ${diff.getMonths} months, ${diff.getDays} days")
// Duration
val duration = Duration.between(date2, LocalDateTime.now())
println(s"${duration.toDays} days, ${duration.toHours} hours")
// Formatting dates
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
println(date2.format(formatter))
// Date functions
println(LocalDate.now().getYear)
println(LocalDate.now().getMonthValue)
println(LocalDate.now().getDayOfMonth)
println(LocalDate.now().getDayOfWeek)
// Date range
val start = LocalDate.of(2024, 1, 1)
val end = LocalDate.of(2024, 1, 10)
val dates = Iterator.iterate(start)(_.plusDays(1)).takeWhile(!_.isAfter(end)).toList
dates.foreach(println)
// Timezone handling
val newYork = ZoneId.of("America/New_York")
val dateInNY = LocalDateTime.now(newYork)
println(dateInNY)
// Parsing dates
val parsed = LocalDate.parse("2024-01-01")
println(parsed)
// Timestamps
val timestamp = System.currentTimeMillis()
println(timestamp)
val dateFromTimestamp = LocalDateTime.ofEpochSecond(timestamp / 1000, 0, ZoneId.systemDefault().getRules.getOffset(Instant.now))
println(dateFromTimestamp)Scala provides regex support through the scala.util.matching.Regex class.
- Create:
"hello".r - Match:
pattern.findFirstIn(text) - Capture groups:
"(\d+)".r - Replace:
text.replaceAll("\d+", "NUM") - Case insensitive:
"(?i)hello".r
// Regular Expressions in Scala
// Create regex
val pattern = "hello".r
val text = "hello world"
// Match
val matchResult = pattern.findFirstIn(text)
println(matchResult)
// Find all
val text2 = "hello world hello again"
val matches = pattern.findAllIn(text2).toList
println(matches.length)
// Regex with capture groups
val datePattern = "(\d{4})-(\d{2})-(\d{2})".r
val text3 = "Date: 2024-01-01"
val datePattern(year, month, day) = text3
println(s"Year: $year, Month: $month, Day: $day")
// Replace with regex
val replaced = "Hello 123 World".replaceAll("\d+", "NUM")
println(replaced)
// Case insensitive
val caseInsensitive = "(?i)hello".r
println(caseInsensitive.findFirstIn("HELLO world"))
// Split with regex
val parts = "Hello World Scala".split("[\s,]+")
parts.foreach(println)
// Pattern matching with regex
val numberPattern = "(\d+)".r
"123" match {
case numberPattern(n) => println(s"Number: $n")
case _ => println("Not a number")
}
// Using Regex with named groups
val namedPattern = "(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})".r
val namedMatch = namedPattern.findFirstMatchIn("2024-01-01")
namedMatch.foreach { m =>
println(s"Year: ${m.group("year")}")
println(s"Month: ${m.group("month")}")
println(s"Day: ${m.group("day")}")
}
// Validating email
val emailPattern = "^[^\s@]+@[^\s@]+\.[^\s@]+$".r
val isValid = emailPattern.matches("test@example.com")
println(s"Email valid: $isValid")Scala supports parallel computing through Futures, parallel collections, actors (Akka), and Java's concurrency utilities.
- Futures:
Future { computation } - Parallel collections:
list.par.map(_ * 2) - Akka actors: Actor-based concurrency
- ForkJoinPool:
new ForkJoinPool(4) - Java Executors:
Executors.newFixedThreadPool(4)
// Parallel Computing in Scala
import scala.concurrent.{Future, Await, ExecutionContext}
import scala.concurrent.duration._
import java.util.concurrent.Executors
// Using Futures (parallel collections)
implicit val ec: ExecutionContext = ExecutionContext.global
val futures = (1 to 10).map { i =>
Future {
Thread.sleep(1000)
i * i
}
}
val results = Await.result(Future.sequence(futures), 10.seconds)
println(results)
// Parallel collections
import scala.collection.parallel.CollectionConverters._
val numbers = (1 to 1000000).toList
val parallelResult = numbers.par.map(_ * 2).toList
println(s"Parallel result size: ${parallelResult.size}")
// Using parallel collections with filters
val evens = (1 to 1000).par.filter(_ % 2 == 0).toList
println(s"Evens: ${evens.size}")
// Using Actors (Akka)
// import akka.actor._
// import akka.routing.RoundRobinPool
// Using ForkJoinPool
import java.util.concurrent.ForkJoinPool
import scala.concurrent.{Await, Future}
val pool = new ForkJoinPool(4)
implicit val ec2: ExecutionContext = ExecutionContext.fromExecutor(pool)
val parallelTask = Future {
(1 to 10).par.map { i =>
Thread.sleep(500)
i * i
}.toList
}
val parallelResult2 = Await.result(parallelTask, 10.seconds)
pool.shutdown()
// Using Java's Executors
val executor = Executors.newFixedThreadPool(4)
implicit val ec3: ExecutionContext = ExecutionContext.fromExecutor(executor)
val tasks = (1 to 10).map { i =>
Future {
Thread.sleep(1000)
i * i
}
}
val combined = Future.sequence(tasks)
val finalResult = Await.result(combined, 10.seconds)
executor.shutdown()
// Using parallel collection operations
val list = (1 to 1000).toList
val parList = list.par
// Map
val squared = parList.map(_ * 2)
// Filter
val filtered = parList.filter(_ % 2 == 0)
// Reduce
val sum = parList.reduce(_ + _)
// Fold
val foldSum = parList.fold(0)(_ + _)
// Aggregate
val aggregateResult = parList.aggregate(0)(_ + _, _ + _)Scala supports metaprogramming through macros, reflection, and type classes for compile-time code generation and runtime inspection.
- Macros: Compile-time code generation
- Reflection:
scala.reflect.runtime - Type classes:
implicitandtype class - Annotations:
@Loggable - Shapeless: Generic programming library
// Metaprogramming in Scala
import scala.reflect.runtime.{universe => ru}
import scala.tools.reflect.ToolBox
// Using reflection to inspect types
def getTypeInfo[A: ru.TypeTag](value: A): Unit = {
val tpe = ru.typeOf[A]
println(s"Type: $tpe")
println(s"Type arguments: ${tpe.typeArgs}")
}
// Macro definition (requires macro paradise)
// import scala.reflect.macros.blackbox.Context
// def addLogImpl(c: Context)(expr: c.Expr[String]): c.Expr[Unit] = {
// import c.universe._
// reify {
// println("Executing: " + expr.splice)
// }
// }
// def addLog(expr: String): Unit = macro addLogImpl
// Using ToolBox for runtime compilation
val tb = ru.runtimeMirror(getClass.getClassLoader).mkToolBox()
// Dynamic method call with reflection
class MyClass {
def greet(name: String): String = s"Hello, $name!"
}
val mirror = ru.runtimeMirror(getClass.getClassLoader)
val instance = new MyClass()
val instanceMirror = mirror.reflect(instance)
val methodSymbol = ru.typeOf[MyClass].decl(ru.TermName("greet")).asMethod
val methodMirror = instanceMirror.reflectMethod(methodSymbol)
val result = methodMirror("Scala").asInstanceOf[String]
println(result)
// Using type tags
def printType[T: ru.TypeTag](value: T): Unit = {
println(ru.typeOf[T])
}
printType(42)
printType("Hello")
// Dynamic class loading
val classLoader = getClass.getClassLoader
val cls = classLoader.loadClass("java.util.ArrayList")
val constructor = cls.getConstructor()
val instance2 = constructor.newInstance()
// Using annotations for metaprogramming
import scala.annotation.StaticAnnotation
class Loggable extends StaticAnnotation
@Loggable
class Service {
def process(): Unit = println("Processing...")
}
// Using type class derivation
trait Show[A] {
def show(value: A): String
}
object Show {
def apply[A](implicit show: Show[A]): Show[A] = show
implicit val intShow: Show[Int] = (value: Int) => value.toString
implicit val stringShow: Show[String] = (value: String) => value
}
// Using Shapeless for generic programming
// libraryDependencies += "com.chuusai" %% "shapeless" % "2.3.10"Scala seamlessly interoperates with Java, allowing direct use of Java classes and libraries.
- Java collections:
new ArrayList[String]() - Convert collections:
list.asScala,scalaSeq.asJava - Java I/O:
new File("file.txt") - Java time:
LocalDate.now() - Java threads:
new Thread(() => ...)
// Interoperability with Java
import java.util.{ArrayList, HashMap}
import java.io.{File, FileReader, BufferedReader}
import java.nio.file.{Paths, Files}
import scala.collection.JavaConverters._
// Using Java collections
val javaList = new ArrayList[String]()
javaList.add("Scala")
javaList.add("Java")
// Convert Java collection to Scala
val scalaList = javaList.asScala.toList
println(scalaList)
// Convert Scala collection to Java
val scalaSeq = Seq("Scala", "Java")
val javaList2 = scalaSeq.asJava
println(javaList2)
// Using Java I/O
val file = new File("example.txt")
val reader = new BufferedReader(new FileReader(file))
val lines = Iterator.continually(reader.readLine()).takeWhile(_ != null).toList
reader.close()
println(lines)
// Using Java NIO
import java.nio.charset.StandardCharsets
val path = Paths.get("example.txt")
val content = new String(Files.readAllBytes(path), StandardCharsets.UTF_8)
println(content)
// Using Java Date and Time
import java.time.{LocalDate, LocalDateTime}
val date = LocalDate.now()
val dateTime = LocalDateTime.now()
// Using Java Optional
import java.util.Optional
val javaOptional = Optional.of("Hello")
val value = if (javaOptional.isPresent) javaOptional.get() else "Default"
println(value)
// Using Java Streams
import java.util.stream.Collectors
val javaStream = javaList.stream()
val filtered = javaStream
.filter(_.startsWith("S"))
.collect(Collectors.toList())
// Using Java generic types
val javaMap = new HashMap[String, Integer]()
javaMap.put("Scala", 3)
javaMap.put("Java", 8)
val scalaMap = javaMap.asScala.mapValues(_.intValue()).toMap
println(scalaMap)
// Using Java threads
val thread = new Thread(() => {
println("Running in Java thread")
})
thread.start()
thread.join()
// Java interop with Scala classes
// Scala class can extend Java class
class MyScalaClass extends java.util.ArrayList[String] {
def addAll(items: Array[String]): Unit = {
items.foreach(add)
}
}Scala performance can be optimized through tail recursion, lazy evaluation, specialization, and compiler flags.
- Tail recursion:
@tailrec - Lazy evaluation:
lazy val,view - Specialization:
@specialized - Inlining:
@inline - Compiler flags:
-optimise,-Xdisable-assertions
// Performance Optimization in Scala
// Performance tips
// 1. Use immutable collections when possible
val immutableList = List(1, 2, 3, 4, 5)
// 2. Use tail recursion
def sumTailRec(list: List[Int], acc: Int = 0): Int = {
list match {
case Nil => acc
case head :: tail => sumTailRec(tail, acc + head)
}
}
// 3. Use lazy evaluation
lazy val expensiveComputation = {
Thread.sleep(1000)
42
}
// 4. Use view for lazy transformations
val numbers = (1 to 1000000).view.map(_ * 2).filter(_ % 2 == 0)
// 5. Use specialization for performance-critical code
import scala.annotation.tailrec
import scala.specialized
def fastSum[@specialized(Int, Long, Double) T](list: List[T])(implicit num: Numeric[T]): T = {
list.foldLeft(num.zero)(num.plus)
}
// 6. Use while loop when needed
def sumWhile(arr: Array[Int]): Int = {
var i = 0
var sum = 0
while (i < arr.length) {
sum += arr(i)
i += 1
}
sum
}
// 7. Use mutable collections for performance
import scala.collection.mutable.ArrayBuffer
val buffer = ArrayBuffer.empty[Int]
for (i <- 0 until 1000000) {
buffer += i
}
// 8. Use String interpolation carefully
def buildString(name: String, age: Int): String = {
s"Name: $name, Age: $age"
}
// 9. Use value classes to avoid allocation
class Wrapper(val value: Int) extends AnyVal
// 10. Use @inline annotation for small methods
import scala.annotation.inline
@inline def add(a: Int, b: Int): Int = a + b
// 11. Use parallel collections for CPU-bound tasks
val parallelResult = (1 to 1000000).par.map(_ * 2).toList
// 12. Profile with VisualVM or JProfiler
// Run with -XX:+PrintGCDetails -XX:+PrintGCTimeStamps
// 13. Use -optimise compiler flag
// scalac -optimise YourFile.scala
// 14. Use -Xdisable-assertions for production
// scalac -Xdisable-assertions YourFile.scala
// 15. Use -Xelide-below for debug levels
// scalac -Xelide-below 0 YourFile.scalaScala provides networking through Java's HTTP client, Akka HTTP, and various third-party libraries.
- HTTP client:
HttpURLConnection - Akka HTTP:
Http().singleRequest - Dispatch:
Http.default(svc OK as.String) - TCP sockets:
new Socket(host, port) - WebSocket: Akka streams
// Networking in Scala
import java.net.{URL, HttpURLConnection, Socket}
import java.io.{BufferedReader, InputStreamReader, PrintWriter}
import scala.io.Source
// HTTP GET request
def get(url: String): String = {
val connection = new URL(url).openConnection().asInstanceOf[HttpURLConnection]
connection.setRequestMethod("GET")
connection.setRequestProperty("User-Agent", "Scala")
val responseCode = connection.getResponseCode
if (responseCode == HttpURLConnection.HTTP_OK) {
val reader = new BufferedReader(new InputStreamReader(connection.getInputStream))
val response = Iterator.continually(reader.readLine()).takeWhile(_ != null).mkString("
")
reader.close()
response
} else {
throw new Exception(s"HTTP error: $responseCode")
}
}
// HTTP POST request
def post(url: String, data: String): String = {
val connection = new URL(url).openConnection().asInstanceOf[HttpURLConnection]
connection.setRequestMethod("POST")
connection.setRequestProperty("Content-Type", "application/json")
connection.setDoOutput(true)
val writer = new PrintWriter(connection.getOutputStream)
writer.write(data)
writer.flush()
writer.close()
val responseCode = connection.getResponseCode
if (responseCode == HttpURLConnection.HTTP_OK) {
val reader = new BufferedReader(new InputStreamReader(connection.getInputStream))
val response = Iterator.continually(reader.readLine()).takeWhile(_ != null).mkString("
")
reader.close()
response
} else {
throw new Exception(s"HTTP error: $responseCode")
}
}
// Using Scala's Source for simple GET
def fetchUrl(url: String): String = {
Source.fromURL(url).mkString
}
// TCP client
def tcpClient(host: String, port: Int, message: String): String = {
val socket = new Socket(host, port)
val writer = new PrintWriter(socket.getOutputStream, true)
val reader = new BufferedReader(new InputStreamReader(socket.getInputStream))
writer.println(message)
val response = reader.readLine()
writer.close()
reader.close()
socket.close()
response
}
// TCP server
def tcpServer(port: Int): Unit = {
val serverSocket = new java.net.ServerSocket(port)
println(s"Server listening on port $port")
while (true) {
val client = serverSocket.accept()
val writer = new PrintWriter(client.getOutputStream, true)
val reader = new BufferedReader(new InputStreamReader(client.getInputStream))
val request = reader.readLine()
writer.println(s"HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\nHello from server!")
writer.close()
reader.close()
client.close()
}
}
// Using Akka HTTP (requires library)
/*
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.model._
import akka.stream.ActorMaterializer
implicit val system = ActorSystem()
implicit val materializer = ActorMaterializer()
val responseFuture = Http().singleRequest(HttpRequest(uri = "https://api.github.com"))
*/
// Using Dispatch (library)
// libraryDependencies += "net.databinder.dispatch" %% "dispatch-core" % "0.13.4"
/*
import dispatch._
val svc = url("https://api.github.com")
val response = Http.default(svc OK as.String)
*/Scala provides JSON support through Play JSON, Circe, and other libraries for encoding/decoding JSON data.
- Play JSON:
Json.toJson(data),Json.parse(json) - Circe:
io.circelibrary - Automatic format:
Json.format[Person] - Pretty print:
Json.prettyPrint(json) - File I/O:
Json.parse(source.mkString)
// Working with JSON in Scala
import scala.util.parsing.json.JSON
import play.api.libs.json._ // Requires library
// Using Play JSON
// libraryDependencies += "com.typesafe.play" %% "play-json" % "2.9.2"
// Define case class
case class Person(name: String, age: Int, city: String, hobbies: List[String])
// Automatic JSON formatting
implicit val personFormat: Format[Person] = Json.format[Person]
// Encode to JSON
val person = Person("Alice", 25, "NYC", List("reading", "coding"))
val json = Json.toJson(person)
val jsonString = Json.stringify(json)
println(jsonString)
// Pretty print
val prettyJson = Json.prettyPrint(json)
println(prettyJson)
// Decode from JSON
val jsonStr = """{"name":"Bob","age":30,"city":"LA","hobbies":["gaming","swimming"]}"""
val parsed = Json.parse(jsonStr)
val decoded = parsed.as[Person]
println(decoded.name)
println(decoded.age)
// Working with arrays
val jsonArray = Json.toJson(List(1, 2, 3, 4, 5))
println(Json.stringify(jsonArray))
// Nested structures
val nestedJson = Json.obj(
"user" -> Json.obj(
"id" -> 1,
"profile" -> Json.obj(
"name" -> "Alice",
"email" -> "alice@example.com"
)
)
)
println(Json.prettyPrint(nestedJson))
// Read JSON from file
val fileContent = scala.io.Source.fromFile("data.json").mkString
val data = Json.parse(fileContent)
// Write JSON to file
val fileWriter = new java.io.PrintWriter("output.json")
fileWriter.write(Json.prettyPrint(json))
fileWriter.close()
// Using JSON with Option
case class User(name: String, age: Option[Int], email: Option[String])
implicit val userFormat: Format[User] = Json.format[User]
val userJson = Json.obj(
"name" -> "Alice"
)
val user = userJson.as[User]
println(user.age.getOrElse(0))
// Custom JSON serialization
implicit val customFormat: Format[Person] = new Format[Person] {
def reads(json: JsValue): JsResult[Person] = {
for {
name <- (json "name").validate[String]
age <- (json "age").validate[Int]
city <- (json "city").validate[String]
hobbies <- (json "hobbies").validate[List[String]]
} yield Person(name, age, city, hobbies)
}
def writes(person: Person): JsValue = {
Json.obj(
"fullname" -> person.name,
"years" -> person.age,
"location" -> person.city,
"activities" -> person.hobbies
)
}
}Scala testing is done using ScalaTest, ScalaCheck, and other testing frameworks.
- ScalaTest:
AnyFlatSpec,Matchers - Assertions:
result should be (expected) - Data providers:
TablewithforAll - ScalaCheck: Property-based testing
- Futures:
ScalaFutures
// Testing in Scala
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import org.scalatest.{BeforeAndAfter, BeforeAndAfterAll}
import org.scalatest.concurrent.ScalaFutures
// Basic test
class MathTest extends AnyFlatSpec with Matchers {
"A calculator" should "add two numbers" in {
val result = 2 + 2
result should be (4)
}
it should "subtract two numbers" in {
val result = 10 - 3
result should be (7)
}
}
// Test with floating point
class FloatTest extends AnyFlatSpec with Matchers {
"Floating point" should "be approximately equal" in {
val result = 0.1 + 0.2
result should be (0.3 +- 0.001)
}
}
// Test with exceptions
class ExceptionTest extends AnyFlatSpec with Matchers {
"Division by zero" should "throw exception" in {
an [ArithmeticException] should be thrownBy {
10 / 0
}
}
}
// Test with collections
class ListTest extends AnyFlatSpec with Matchers {
val list = List(1, 2, 3, 4, 5)
"A list" should "have correct length" in {
list should have length 5
}
it should "contain specific elements" in {
list should contain (3)
}
it should "be sorted" in {
list shouldBe sorted
}
}
// Test with fixtures
class FixtureTest extends AnyFlatSpec with Matchers with BeforeAndAfter {
var value: Int = 0
before {
value = 42
}
after {
value = 0
}
"A fixture" should "be set up" in {
value should be (42)
}
}
// Test with data providers (tables)
class TableTest extends AnyFlatSpec with Matchers {
val additionData = Table(
("a", "b", "expected"),
(1, 2, 3),
(0, 0, 0),
(-1, 1, 0),
(5, -3, 2)
)
forAll(additionData) { (a, b, expected) =>
s"Adding $a and $b" should s"be $expected" in {
val result = a + b
result should be (expected)
}
}
}
// Test with Property-based testing (ScalaCheck)
import org.scalacheck.Properties
import org.scalacheck.Prop.forAll
object MathProps extends Properties("Math") {
property("addition is associative") = forAll { (a: Int, b: Int, c: Int) =>
(a + b) + c == a + (b + c)
}
}
// Test with ScalaFutures
import scala.concurrent.{Future, Await}
import scala.concurrent.duration._
class FutureTest extends AnyFlatSpec with Matchers with ScalaFutures {
implicit val patience: PatienceConfig = PatienceConfig(timeout = 5.seconds)
"A future" should "complete successfully" in {
val future = Future.successful(42)
whenReady(future) { result =>
result should be (42)
}
}
}
// Running tests
// sbt test
// sbt testOnly MathTest
// Using scalatest with sbt
// in build.sbt:
// libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.15" % TestScala debugging is done through logging, assertions, and IDEs with breakpoint support.
- println:
println("debug") - Logging:
logger.info("message") - Assertions:
assert(condition),require(condition) - Try:
Try(expression) - IDE debugger: IntelliJ IDEA, Eclipse
// Debugging in Scala
// Using println for debugging
def debugFunction(x: Int): Int = {
println(s"Entering function with x = $x")
val result = x * 2
println(s"Result = $result")
result
}
debugFunction(5)
// Using log4j for logging
// libraryDependencies += "org.apache.logging.log4j" %% "log4j-api-scala" % "12.0"
/*
import org.apache.logging.log4j.scala.Logging
class MyClass extends Logging {
def doSomething(): Unit = {
logger.info("Doing something")
logger.debug("Debug information")
logger.error("Error occurred")
}
}
*/
// Using Scala's logging (built-in)
import scala.util.logging.Logged
object Logger extends Logged {
def process(): Unit = {
log("Processing started")
log("Processing completed")
}
}
// Using assert
def assertExample(x: Int): Unit = {
assert(x > 0, "x must be positive")
println(s"x is positive: $x")
}
// Using require
def requireExample(x: Int): Unit = {
require(x > 0, "x must be positive")
println(s"x is positive: $x")
}
// Using assume
def assumeExample(x: Int): Unit = {
assume(x > 0, "x must be positive")
println(s"x is positive: $x")
}
// Using StackTrace
try {
throw new Exception("Something went wrong")
} catch {
case e: Exception =>
println(s"Error: ${e.getMessage}")
e.printStackTrace()
}
// Using scala.util.Try for debugging
import scala.util.{Try, Success, Failure}
def divideWithTry(a: Int, b: Int): Try[Int] = {
Try(a / b)
}
divideWithTry(10, 2) match {
case Success(value) => println(s"Result: $value")
case Failure(e) => println(s"Error: ${e.getMessage}")
}
// Using JVM debugging flags
// -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005
// Using ScalaTest's Debugger
// Run tests with -Dtest.debug=true
// Using SBT console for interactive debugging
// sbt console
// :load MyScript.scala
// Using IntelliJ IDEA debugger
// Set breakpoints and run in debug mode
// Using VisualVM for profiling
// jvisualvm
// Using JConsole for monitoring
// jconsole
// Using -Xprint:typer for compiler debugging
// scalac -Xprint:typer MyFile.scala
// Using -Ydebug for debug information
// scalac -Ydebug MyFile.scalaAbstract classes and traits define contracts and reusable behavior in Scala's type system.
- Abstract class:
abstract class Animal { def makeSound(): String } - Concrete class:
class Dog extends Animal - Trait:
trait SoundMaker { def makeSound(): String } - Multiple traits:
class Lion extends SoundMaker with Named - Self-type:
trait Service { self: Logger => ... }
// Abstract Classes and Traits in Scala
// Abstract class
abstract class Animal {
val name: String
val age: Int
def makeSound(): String
}
// Concrete implementation
class Dog(val name: String, val age: Int) extends Animal {
def makeSound(): String = "Woof!"
}
class Cat(val name: String, val age: Int) extends Animal {
def makeSound(): String = "Meow!"
}
// Trait (interface with implementation)
trait SoundMaker {
def makeSound(): String
}
trait Named {
def name: String
}
// Class implementing multiple traits
class Lion(val name: String) extends SoundMaker with Named {
def makeSound(): String = "Roar!"
}
// Trait with abstract methods
trait Logger {
def log(message: String): Unit
def info(message: String): Unit = log(s"INFO: $message")
def error(message: String): Unit = log(s"ERROR: $message")
}
// Abstract type members
trait Container {
type A
def value: A
}
class IntContainer(val value: Int) extends Container {
type A = Int
}
// Self-type annotation
trait Service {
self: Logger =>
def process(): Unit = {
info("Processing started")
// processing logic
info("Processing completed")
}
}
// Usage
val dog: Animal = new Dog("Rex", 3)
val cat: Animal = new Cat("Whiskers", 2)
val lion: Lion = new Lion("Simba")
println(dog.makeSound())
println(cat.makeSound())
println(lion.makeSound())
// Type checking
println(dog.isInstanceOf[Animal])
println(dog.isInstanceOf[Dog])
println(dog.isInstanceOf[Cat])Generic types in Scala enable type-safe programming with parameterized types, type bounds, and variance.
- Generic class:
class Box[A](val value: A) - Type bounds:
[A <: AnyRef],[A >: String] - Variance:
class Covariant[+A],class Contravariant[-A] - Higher-kinded:
trait Functor[F[_]] - Type aliases:
type IntList = List[Int]
// Generic Types in Scala
// Generic class
class Box[A](val value: A) {
def get: A = value
def map[B](f: A => B): Box[B] = new Box(f(value))
}
// Generic trait
trait Container[A] {
def get: A
def put(value: A): Container[A]
}
// Generic function
def identity[A](x: A): A = x
// Generic with multiple type parameters
class Pair[A, B](val first: A, val second: B)
// Type bounds
class UpperBound[A <: AnyRef](val value: A)
class LowerBound[A >: String](val value: A)
// Context bounds
def printLength[A: Seq](seq: A): Int = seq.length
// View bounds (deprecated in Scala 2.13)
// def printString[A <% String](value: A): String = value
// Covariant
class Covariant[+A](val value: A)
// Contravariant
class Contravariant[-A] {
def process(value: A): Unit = println(value)
}
// Invariant
class Invariant[A](val value: A)
// Type aliases
type IntList = List[Int]
type StringMap = Map[String, String]
// Higher-kinded types
trait Functor[F[_]] {
def map[A, B](fa: F[A])(f: A => B): F[B]
}
// Usage
val box: Box[Int] = new Box(42)
val mapped: Box[String] = box.map(_.toString)
val pair: Pair[String, Int] = new Pair("Hello", 42)
val upper: UpperBound[String] = new UpperBound("Hello")
// val lower: LowerBound[String] = new LowerBound("World")
val covariant: Covariant[String] = new Covariant("Hello")
val covariant2: Covariant[Any] = covariant
val list: IntList = List(1, 2, 3)
val map: StringMap = Map("a" -> "b", "c" -> "d")Implicit conversions and type classes in Scala enable extension methods, type class derivation, and compile-time polymorphism.
- Implicit conversion:
implicit def intToString(x: Int): String = x.toString - Implicit class:
implicit class RichInt(val value: Int) - Type class:
trait Show[A] - Implicit parameters:
def process[A: Show](value: A) - Context bounds:
[A: Show]
// Implicit Conversions and Type Classes
// Implicit conversion (use with caution)
implicit def intToString(x: Int): String = x.toString
val str: String = 42 // Will implicitly convert
// Implicit class
implicit class RichInt(val value: Int) {
def square: Int = value * value
def cube: Int = value * value * value
}
println(5.square)
println(5.cube)
// Type class pattern
trait Show[A] {
def show(value: A): String
}
object Show {
def apply[A](implicit instance: Show[A]): Show[A] = instance
implicit val intShow: Show[Int] = (value: Int) => value.toString
implicit val stringShow: Show[String] = (value: String) => value
implicit val booleanShow: Show[Boolean] = (value: Boolean) => value.toString
}
// Using type class
def printShow[A: Show](value: A): Unit = {
println(implicitly[Show[A]].show(value))
}
printShow(42)
printShow("Hello")
printShow(true)
// Implicit parameter
def greet(implicit name: String): String = s"Hello, $name!"
implicit val defaultName: String = "Scala"
println(greet)
// Implicitly resolving
val showInt = implicitly[Show[Int]]
println(showInt.show(100))
// Context bound (shorthand for implicit parameter)
def process[A: Show](value: A): String = {
val showInstance = implicitly[Show[A]]
showInstance.show(value)
}
// Implicit conversion with DummyImplicit
def processInt(x: Int)(implicit d: DummyImplicit): Unit = {
println(s"Processing int: $x")
}
// Using implicit evidence
sealed trait Evidence
object Evidence {
implicit object IntEvidence extends Evidence
}
def requireEvidence[A](value: A)(implicit ev: Evidence): Unit = {
println(s"Processing: $value")
}
requireEvidence(42) // Works with implicit Evidence
// Implicitly for type class derivation
trait Eq[A] {
def equal(a: A, b: A): Boolean
}
object Eq {
def apply[A](implicit instance: Eq[A]): Eq[A] = instance
}
implicit val intEq: Eq[Int] = (a: Int, b: Int) => a == b
def compare[A: Eq](a: A, b: A): Boolean = {
Eq[A].equal(a, b)
}
println(compare(5, 5))
println(compare(5, 6))Scala supports lazy evaluation through lazy val, LazyList, and view for efficient computation.
- Lazy val:
lazy val x = expensive() - LazyList:
LazyList.from(1).map(_ * 2) - View:
(1 to 1000000).view.map(_ * 2) - Stream:
LazyList.unfold(0)(state => if (state > 10) None else Some((state, state + 1))) - By-name parameters:
def lazyIf(condition: => Boolean)(thenBlock: => Any)
// Lazy Evaluation and Streams
// Lazy val
lazy val expensiveValue: Int = {
println("Computing expensive value")
Thread.sleep(1000)
42
}
// Lazy list (Stream - deprecated in Scala 2.13)
// Use LazyList instead
val lazyList: LazyList[Int] = LazyList.from(1)
// LazyList with infinite sequence
val fibs: LazyList[Int] = {
def fib(a: Int, b: Int): LazyList[Int] = a #:: fib(b, a + b)
fib(0, 1)
}
println(fibs.take(10).toList)
// LazyList with map
val squares: LazyList[Int] = LazyList.from(1).map(_ * 2)
println(squares.take(10).toList)
// LazyList with filter
val evens: LazyList[Int] = LazyList.from(1).filter(_ % 2 == 0)
println(evens.take(10).toList)
// LazyList with takeWhile
val numbers: LazyList[Int] = LazyList.from(1).takeWhile(_ <= 100)
println(numbers.toList)
// Using view for lazy transformations
val viewList = (1 to 1000000).view.map(_ * 2).filter(_ % 2 == 0)
println(viewList.take(10).toList)
// Lazy evaluation with by-name parameters
def lazyIf(condition: => Boolean)(thenBlock: => Any)(elseBlock: => Any): Any = {
if (condition) thenBlock else elseBlock
}
// Streaming using Iterator
val iterator: Iterator[Int] = Iterator.from(1)
println(iterator.take(10).toList)
// Using Stream with unfold
val stream: LazyList[Int] = LazyList.unfold(0) { state =>
if (state > 10) None else Some((state, state + 1))
}
println(stream.toList)
// Lazy evaluation in collections
val lazyMap = Map(1 -> "one", 2 -> "two", 3 -> "three")
val lazyMapResult = lazyMap.view.mapValues(_.toUpperCase).toMap
// Using lazy val in classes
class LazyClass {
lazy val computed: Int = {
println("Computing")
42
}
}
val instance = new LazyClass
println(instance.computed) // First access triggers computation
println(instance.computed) // Returns cached value
// LazyList with recursion
def countdown(n: Int): LazyList[Int] = {
if (n <= 0) LazyList.empty
else n #:: countdown(n - 1)
}
println(countdown(10).toList)Scala provides advanced collection operations including matrix operations, element-wise transformations, and functional programming methods.
- Matrix ops:
Array.tabulate,grouped - Element-wise:
map,zip - Transpose:
matrix.indices.map(i => matrix.map(_(i))) - Norm:
math.sqrt(matrix.flatten.map(x => x*x).sum) - Trace:
matrix.indices.map(i => matrix(i)(i)).sum
// Advanced Collections Operations
// Collection initialization
val zeros = Array.fill(3, 3)(0)
val ones = Array.fill(3, 3)(1)
val identity = Array.tabulate(3, 3)((i, j) => if (i == j) 1 else 0)
// Reshaping
val arr = (1 to 9).toArray
val matrix = arr.grouped(3).toArray
// Transpose
def transpose[A](matrix: Array[Array[A]]): Array[Array[A]] = {
val rows = matrix.length
val cols = matrix(0).length
Array.tabulate(cols, rows)((i, j) => matrix(j)(i))
}
// Element-wise operations
val A = Array.tabulate(3, 3)((i, j) => i * 3 + j + 1)
val B = A.map(_.map(_ + 1))
val C = A.map(_.map(_ * 2))
val D = A.map(_.map(x => x * x))
// Matrix multiplication
def matMul(A: Array[Array[Double]], B: Array[Array[Double]]): Array[Array[Double]] = {
val rows = A.length
val cols = B(0).length
val inner = B.length
Array.tabulate(rows, cols) { (i, j) =>
(0 until inner).map(k => A(i)(k) * B(k)(j)).sum
}
}
val X = Array.tabulate(3, 3)((_, _) => math.random())
val Y = Array.tabulate(3, 3)((_, _) => math.random())
val Z = matMul(X, Y)
// Element-wise multiplication
val W = X.zip(Y).map { case (rowX, rowY) =>
rowX.zip(rowY).map { case (x, y) => x * y }
}
// Matrix norm (Frobenius)
def norm(matrix: Array[Array[Double]]): Double = {
math.sqrt(matrix.flatten.map(x => x * x).sum)
}
// Trace
def trace(matrix: Array[Array[Double]]): Double = {
matrix.indices.map(i => matrix(i)(i)).sum
}
// Diagonal
def diag(matrix: Array[Array[Double]]): Array[Double] = {
matrix.indices.map(i => matrix(i)(i)).toArray
}
// Using Breeze for advanced operations
/*
import breeze.linalg._
val A = DenseMatrix((1.0, 2.0), (3.0, 4.0))
val B = DenseMatrix((5.0, 6.0), (7.0, 8.0))
val C = A * B
val D = A + B
val E = A.t
val F = A \ B
*/
println(s"Norm: ${norm(X)}")
println(s"Trace: ${trace(X)}")
println(s"Diagonal: ${diag(X).mkString(", ")}")Scala handles missing data using Option, Either, and Try for safe error handling.
- Option:
Some(value)orNone - Get with default:
option.getOrElse(default) - Either:
Left(error)orRight(value) - Try:
Try(expression) - For-comprehension:
for (a <- optA; b <- optB) yield a + b
// Handling Missing Data (Option and Either)
// Using Option
val data: List[Option[Int]] = List(Some(1), Some(2), None, Some(4), Some(5), None, Some(7))
// Check for missing values
val hasMissing: Boolean = data.contains(None)
println(s"Has missing: $hasMissing")
// Remove missing values
val cleanData: List[Int] = data.flatten
println(cleanData)
// Replace missing values
val replaced: List[Int] = data.map(_.getOrElse(0))
println(replaced)
// Operations with missing values
val x: List[Option[Int]] = List(Some(1), Some(2), None, Some(4))
val y: List[Option[Int]] = List(Some(5), Some(6), None, Some(8))
val z: List[Option[Int]] = x.zip(y).map { case (a, b) =>
for {
va <- a
vb <- b
} yield va + vb
}
println(z)
// Ignoring missing values
val sumComplete: Int = x.flatten.sum
println(s"Sum of complete data: $sumComplete")
// Using Option in collections
val numbers = List(1, 2, 3, 4, 5)
val firstEven = numbers.find(_ % 2 == 0)
println(firstEven)
// Using Either for error handling
def safeDivide(a: Int, b: Int): Either[String, Int] = {
if (b == 0) Left("Cannot divide by zero")
else Right(a / b)
}
safeDivide(10, 2) match {
case Right(value) => println(s"Result: $value")
case Left(error) => println(s"Error: $error")
}
safeDivide(10, 0) match {
case Right(value) => println(s"Result: $value")
case Left(error) => println(s"Error: $error")
}
// Using Try for error handling
import scala.util.{Try, Success, Failure}
def divideTry(a: Int, b: Int): Try[Int] = Try(a / b)
divideTry(10, 2) match {
case Success(value) => println(s"Result: $value")
case Failure(e) => println(s"Error: ${e.getMessage}")
}
// Combining Options with for-comprehension
val optA: Option[Int] = Some(10)
val optB: Option[Int] = Some(20)
val result: Option[Int] = for {
a <- optA
b <- optB
} yield a + b
println(result)
// Using Option.getOrElse
val value: Int = data.headOption.getOrElse(0)
// Using Option.orElse
val default: Option[Int] = None
val finalValue: Option[Int] = Some(42).orElse(default)
// Using Option.fold
val processed: Int = Some(42).fold(0)(_ * 2)Scala provides sorting and searching through sorted, sortBy, find, and binarySearch.
- Sort:
list.sorted,list.sortBy(_.age) - Custom comparator:
list.sortWith(_ > _) - Search:
list.find(_ > 5),list.filter(_ > 5) - Binary search:
java.util.Arrays.binarySearch(array, target) - Contains:
list.contains(7)
// Sorting and Searching in Scala
// Basic sorting
val arr = List(5, 2, 8, 1, 9, 3)
val sorted = arr.sorted
println(sorted)
// Sorting with custom comparator
val arr2 = List((5, "apple"), (3, "banana"), (8, "cherry"))
val sorted2 = arr2.sortBy(_._1)
println(sorted2)
// Sorting descending
val arr3 = List(5, 2, 8, 1, 9, 3)
val sorted3 = arr3.sortWith(_ > _)
println(sorted3)
// Sorting with custom comparator
val sorted4 = arr3.sortWith((a, b) => a < b)
println(sorted4)
// Search functions
val arr5 = List(1, 3, 5, 7, 9, 11)
val greaterThan5 = arr5.filter(_ > 5)
println(greaterThan5)
val firstGreaterThan5 = arr5.find(_ > 5)
println(firstGreaterThan5)
val lastGreaterThan5 = arr5.reverse.find(_ > 5)
println(lastGreaterThan5)
// Contains
val hasSeven = arr5.contains(7)
val hasFour = arr5.contains(4)
println(s"Has 7: $hasSeven, Has 4: $hasFour")
// Binary search (requires sorted)
val arr6 = Array(1, 2, 3, 4, 5, 6, 7)
val index = java.util.Arrays.binarySearch(arr6, 5)
println(s"Found at index: $index")
// Custom binary search
def binarySearch[T: Ordering](arr: Array[T], target: T): Int = {
val ord = implicitly[Ordering[T]]
var left = 0
var right = arr.length - 1
while (left <= right) {
val mid = left + (right - left) / 2
val cmp = ord.compare(arr(mid), target)
if (cmp == 0) return mid
else if (cmp < 0) left = mid + 1
else right = mid - 1
}
-1
}
val arr7 = Array(1, 2, 3, 4, 5, 6, 7)
val index2 = binarySearch(arr7, 5)
println(s"Found at index: $index2")
// Using sort with implicit ordering
implicit val reverseOrdering: Ordering[Int] = Ordering[Int].reverse
val sorted5 = List(5, 2, 8, 1, 9, 3).sorted
println(sorted5)Scala provides mathematical operations through scala.math and external libraries like Breeze.
- Arithmetic:
+,-,*,/,% - Trigonometric:
math.sin,math.cos,math.tan - Statistics:
data.sum, custom functions - Linear algebra: Breeze library
- Random:
math.random
// Mathematical Operations in Scala
// Basic arithmetic
val x = 10
val y = 3
println(s"x + y = ${x + y}")
println(s"x - y = ${x - y}")
println(s"x * y = ${x * y}")
println(s"x / y = ${x / y}")
println(s"x % y = ${x % y}")
println(s"x ^ y = ${math.pow(x, y)}")
// Mathematical functions
val pi = math.Pi
println(s"sin(pi/4) = ${math.sin(pi / 4)}")
println(s"cos(pi/4) = ${math.cos(pi / 4)}")
println(s"tan(pi/4) = ${math.tan(pi / 4)}")
println(s"exp(1) = ${math.exp(1)}")
println(s"log(e) = ${math.log(math.exp(1))}")
println(s"log10(100) = ${math.log10(100)}")
println(s"sqrt(9) = ${math.sqrt(9)}")
// Special functions
println(s"abs(-5) = ${math.abs(-5)}")
println(s"ceil(3.14) = ${math.ceil(3.14)}")
println(s"floor(3.14) = ${math.floor(3.14)}")
println(s"round(3.14) = ${math.round(3.14)}")
println(s"max(1, 3, 5, 2, 4) = ${math.max(math.max(math.max(math.max(1, 3), 5), 2), 4)}")
println(s"min(1, 3, 5, 2, 4) = ${math.min(math.min(math.min(math.min(1, 3), 5), 2), 4)}")
// Random numbers
println(s"Random: ${math.random()}")
// Statistics (using Scala's standard library)
val data = (1 to 10).map(_.toDouble)
println(s"sum = ${data.sum}")
println(s"mean = ${data.sum / data.length}")
println(s"min = ${data.min}")
println(s"max = ${data.max}")
// Complex numbers (using spire or scala-math)
/*
import spire.math._
import spire.implicits._
val c1 = Complex(1.0, 2.0)
val c2 = Complex(3.0, 4.0)
val c3 = c1 + c2
val c4 = c1 * c2
*/
// Using Breeze for linear algebra
/*
import breeze.linalg._
val A = DenseMatrix((1.0, 2.0), (3.0, 4.0))
val B = DenseMatrix((5.0, 6.0), (7.0, 8.0))
val C = A * B
val D = A + B
val E = A.t
*/
// Using Apache Commons Math
// libraryDependencies += "org.apache.commons" % "commons-math3" % "3.6.1"
/*
import org.apache.commons.math3.stat.StatUtils
import org.apache.commons.math3.linear._
val data2 = Array(1.0, 2.0, 3.0, 4.0, 5.0)
println(StatUtils.mean(data2))
println(StatUtils.variance(data2))
val matrix = new Array2DRowRealMatrix(Array(
Array(1.0, 2.0),
Array(3.0, 4.0)
))
val inverse = new LUDecomposition(matrix).getSolver().getInverse()
*/Scala provides data serialization through Java serialization, JSON, Pickling, XML, and libraries like Avro.
- Java serialization:
ObjectOutputStream - JSON: Play JSON, Circe
- Pickling:
scala.pickling - XML:
scala.xml - YAML: SnakeYAML
// Data Serialization in Scala
import java.io.{ObjectOutputStream, ObjectInputStream, FileOutputStream, FileInputStream}
// Using Java serialization
class Person(val name: String, val age: Int) extends Serializable
val person = new Person("Alice", 25)
// Serialize
val out = new ObjectOutputStream(new FileOutputStream("person.ser"))
out.writeObject(person)
out.close()
// Deserialize
val in = new ObjectInputStream(new FileInputStream("person.ser"))
val deserialized = in.readObject().asInstanceOf[Person]
in.close()
println(s"Name: ${deserialized.name}, Age: ${deserialized.age}")
// Using Pickling (requires library)
// libraryDependencies += "org.scala-lang.modules" %% "scala-pickling" % "1.0.0"
/*
import scala.pickling._
import scala.pickling.Defaults._
case class User(name: String, age: Int)
val user = User("Alice", 25)
val pickle = user.pickle
val unpickled = pickle.unpickle[User]
*/
// Using JSON (Play JSON)
import play.api.libs.json._
case class UserJson(name: String, age: Int, hobbies: List[String])
implicit val userFormat: Format[UserJson] = Json.format[UserJson]
val user = UserJson("Alice", 25, List("reading", "coding"))
val json = Json.toJson(user)
val jsonString = Json.stringify(json)
println(jsonString)
val parsed = Json.parse(jsonString).as[UserJson]
println(parsed.name)
// Using CSV
def toCSV(data: List[List[String]]): String = {
data.map(_.mkString(",")).mkString("
")
}
val csvData = List(
List("Name", "Age", "City"),
List("Alice", "25", "NYC"),
List("Bob", "30", "LA")
)
val csvString = toCSV(csvData)
println(csvString)
// Using XML
import scala.xml._
val xml = <person name="Alice" age="25">
<hobbies>
<hobby>reading</hobby>
<hobby>coding</hobby>
</hobbies>
</person>
println(xml)
val name = xml "@name"
val age = xml "@age"
// Using YAML (requires library)
// libraryDependencies += "org.yaml" % "snakeyaml" % "1.30"
/*
import org.yaml.snakeyaml.Yaml
val yaml = new Yaml()
val data = Map("name" -> "Alice", "age" -> 25)
val yamlString = yaml.dump(data)
println(yamlString)
*/
// Using Protocol Buffers (requires library)
// libraryDependencies += "com.google.protobuf" % "protobuf-java" % "3.21.12"
// Using Avro (requires library)
// libraryDependencies += "org.apache.avro" % "avro" % "1.11.1"Scala interfaces with external systems through JDBC, Slick, Redis clients, HTTP, and shell commands.
- Database:
java.sql.DriverManager, Slick - Redis:
com.redis.RedisClient - HTTP:
java.net.HttpURLConnection - Shell:
scala.sys.process._ - Environment:
sys.env,sys.props
// Interfacing with External Systems
import java.sql.{DriverManager, Connection, ResultSet}
// Database connection (JDBC)
def queryDatabase(): Unit = {
val url = "jdbc:postgresql://localhost:5432/test"
val user = "user"
val password = "pass"
try {
val connection = DriverManager.getConnection(url, user, password)
val statement = connection.createStatement()
val resultSet = statement.executeQuery("SELECT * FROM users WHERE id = 1")
while (resultSet.next()) {
val name = resultSet.getString("name")
println(s"User: $name")
}
resultSet.close()
statement.close()
connection.close()
} catch {
case e: Exception => println(s"Database error: ${e.getMessage}")
}
}
// Using Slick (functional database library)
/*
import slick.jdbc.PostgresProfile.api._
import scala.concurrent.Await
import scala.concurrent.duration._
class Users(tag: Tag) extends Table[(Int, String)](tag, "users") {
def id = column[Int]("id", O.PrimaryKey)
def name = column[String]("name")
def * = (id, name)
}
val users = TableQuery[Users]
val db = Database.forConfig("postgres")
val query = users.filter(_.id === 1).result
val result = Await.result(db.run(query), 5.seconds)
result.foreach { case (id, name) => println(s"User: $name") }
*/
// Using Redis (requires library)
// libraryDependencies += "net.debasishg" %% "redisclient" % "3.42"
/*
import com.redis._
val client = new RedisClient("localhost", 6379)
client.set("key", "value")
val value = client.get("key")
println(value)
*/
// Using HTTP client
import java.net.HttpURLConnection
import java.io.{BufferedReader, InputStreamReader}
def httpGet(url: String): String = {
val connection = new java.net.URL(url).openConnection().asInstanceOf[HttpURLConnection]
connection.setRequestMethod("GET")
connection.setRequestProperty("User-Agent", "Scala")
val reader = new BufferedReader(new InputStreamReader(connection.getInputStream))
val response = Iterator.continually(reader.readLine()).takeWhile(_ != null).mkString("
")
reader.close()
connection.disconnect()
response
}
val response = httpGet("https://api.github.com")
println(response.take(500))
// Using Shell commands
import scala.sys.process._
def executeCommand(cmd: String): String = {
cmd.!!.trim
}
val output = executeCommand("ls -la")
println(output)
// Using environment variables
val envVar = sys.env.getOrElse("HOME", "Not set")
println(s"HOME: $envVar")
// Using System properties
val osName = sys.props.getOrElse("os.name", "Unknown")
println(s"OS: $osName")Reverse a string using reverse, manual iteration, or recursion.
- Built-in:
s.reverse - Manual:
s.foldLeft("")((acc, c) => c + acc) - Recursive:
if (s.isEmpty) "" else reverse(s.tail) + s.head - Performance: O(n) time
// Reverse a string
def reverseString(s: String): String = s.reverse
def reverseStringManual(s: String): String = {
s.foldLeft("")((acc, c) => c + acc)
}
def reverseStringRecursive(s: String): String = {
if (s.length <= 1) s
else reverseStringRecursive(s.tail) + s.head
}
val s = "hello"
println(s"Original: $s")
println(s"Reversed: ${reverseString(s)}")
println(s"Reversed (manual): ${reverseStringManual(s)}")
println(s"Reversed (recursive): ${reverseStringRecursive(s)}")Check if a string is a palindrome by comparing characters from both ends.
- Built-in:
s == s.reverse - Manual: Two-pointer comparison
- Recursive:
s.head == s.last && isPalindrome(s.tail.init) - Case insensitive:
s.toLowerCase
// Check palindrome
def isPalindrome(s: String): Boolean = {
val cleaned = s.toLowerCase.replaceAll(" ", "")
cleaned == cleaned.reverse
}
def isPalindromeManual(s: String): Boolean = {
val cleaned = s.toLowerCase.replaceAll(" ", "")
val chars = cleaned.toCharArray
var i = 0
var j = chars.length - 1
while (i < j) {
if (chars(i) != chars(j)) return false
i += 1
j -= 1
}
true
}
def isPalindromeRecursive(s: String): Boolean = {
val cleaned = s.toLowerCase.replaceAll(" ", "")
if (cleaned.length <= 1) true
else if (cleaned.head != cleaned.last) false
else isPalindromeRecursive(cleaned.substring(1, cleaned.length - 1))
}
val strings = List("racecar", "hello", "A man a plan a canal Panama", "race a car")
strings.foreach { s =>
println(s""""$s" is palindrome: ${isPalindrome(s)}""")
}Find the maximum value using max, iteration, or recursion.
- Built-in:
arr.max - Manual:
var max = arr(0); for (i <- 1 until arr.length) { if (arr(i) > max) max = arr(i) } - Recursive:
if (arr.isEmpty) null else ... - Reduce:
arr.reduce(_ max _)
// Find max in array
def findMax(arr: Array[Int]): Int = arr.max
def findMaxManual(arr: Array[Int]): Int = {
if (arr.isEmpty) throw new IllegalArgumentException("Array is empty")
var max = arr(0)
for (i <- 1 until arr.length) {
if (arr(i) > max) max = arr(i)
}
max
}
def findMaxRecursive(arr: Array[Int], index: Int = 0, max: Int = Int.MinValue): Int = {
if (index >= arr.length) max
else findMaxRecursive(arr, index + 1, if (arr(index) > max) arr(index) else max)
}
val arr = Array(1, 5, 3, 9, 2)
println(s"Array: ${arr.mkString(", ")}")
println(s"Max: ${findMax(arr)}")
println(s"Max (manual): ${findMaxManual(arr)}")
println(s"Max (recursive): ${findMaxRecursive(arr)}")Remove duplicates using distinct, manual fold, or Set.
- Built-in:
list.distinct - Manual:
list.foldLeft(List.empty[T])((acc, item) => if (acc.contains(item)) acc else acc :+ item) - Set:
list.toSet.toList - Preserve order: Manual fold
// Remove duplicates
def removeDuplicates[T](list: List[T]): List[T] = list.distinct
def removeDuplicatesManual[T](list: List[T]): List[T] = {
list.foldLeft(List.empty[T]) { (acc, item) =>
if (acc.contains(item)) acc else acc :+ item
}
}
def removeDuplicatesSet[T](list: List[T]): List[T] = list.toSet.toList
val list = List("apple", "banana", "apple", "orange", "banana", "grape")
println(s"Original: ${list.mkString(", ")}")
println(s"Without duplicates: ${removeDuplicates(list).mkString(", ")}")
println(s"Without duplicates (manual): ${removeDuplicatesManual(list).mkString(", ")}")
println(s"Without duplicates (set): ${removeDuplicatesSet(list).mkString(", ")}")Merge arrays using ++, concat, or sorted merge.
- Concatenate:
arr1 ++ arr2 - Sorted merge:
mergeSorted(arr1, arr2) - Unique:
(arr1 ++ arr2).distinct - Performance: O(n) time
// Merge arrays
def mergeArrays[T](arr1: Array[T], arr2: Array[T]): Array[T] = arr1 ++ arr2
def mergeSorted(arr1: Array[Int], arr2: Array[Int]): Array[Int] = {
val result = Array.newBuilder[Int]
var i = 0
var j = 0
while (i < arr1.length && j < arr2.length) {
if (arr1(i) <= arr2(j)) {
result += arr1(i)
i += 1
} else {
result += arr2(j)
j += 1
}
}
while (i < arr1.length) {
result += arr1(i)
i += 1
}
while (j < arr2.length) {
result += arr2(j)
j += 1
}
result.result()
}
def mergeUnique[T](arr1: Array[T], arr2: Array[T]): Array[T] = {
(arr1 ++ arr2).distinct
}
val arr1 = Array(1, 2, 3)
val arr2 = Array(4, 5, 6)
println(s"Merged: ${mergeArrays(arr1, arr2).mkString(", ")}")
val sorted1 = Array(1, 3, 5, 7)
val sorted2 = Array(2, 4, 6, 8)
println(s"Merged sorted: ${mergeSorted(sorted1, sorted2).mkString(", ")}")Convert string to number using toInt, toDouble, or toFloat.
- Int:
s.toInt - Double:
s.toDouble - Float:
s.toFloat - Safe:
Try(s.toInt).getOrElse(0)
// Convert string to number
def stringToNumber(s: String): Double = s.toDouble
def stringToInt(s: String): Int = s.toInt
def stringToFloat(s: String): Float = s.toFloat
def stringToNumberSafe(s: String): Double = {
try {
s.toDouble
} catch {
case _: NumberFormatException => 0.0
}
}
val strings = List("42", "3.14", "hello", "123", "45.67")
strings.foreach { s =>
println(s""""$s" -> int: ${stringToInt(s)}, float: ${stringToFloat(s)}""")
}Iterate through a map using foreach or for comprehension.
- foreach:
map.foreach { case (k, v) => ... } - for:
for ((k, v) <- map) { ... } - Keys:
map.keys - Find key:
map.get(key)
// Loop through dictionary (Map)
def loopMap(map: Map[String, Any]): Unit = {
map.foreach { case (key, value) =>
println(s"$key => $value")
}
}
def findKey[V](map: Map[String, V], key: String): Option[V] = map.get(key)
val data = Map("name" -> "Alice", "age" -> 25, "city" -> "NYC")
println("Dictionary:")
loopMap(data)
println()
val name = findKey(data, "name")
println(s"Name: ${name.getOrElse("Not found")}")
val country = findKey(data, "country")
println(s"Country: ${country.getOrElse("Not found")}")Delay execution using Thread.sleep or Future for async.
- Blocking:
Thread.sleep(seconds * 1000) - Async:
Future { Thread.sleep(delay); callback } - Callback:
delayWithCallback(seconds)(callback)(resultCallback) - Use case: Scheduling
// Delay function execution
def delaySeconds(seconds: Long)(callback: => Unit): Unit = {
Thread.sleep(seconds * 1000)
callback
}
def delayAsync(seconds: Long)(callback: => Unit): Future[Unit] = {
Future {
Thread.sleep(seconds * 1000)
callback
}
}
def delayWithCallback(seconds: Long)(callback: => Unit)(resultCallback: => Unit): Future[Unit] = {
Future {
Thread.sleep(seconds * 1000)
callback
resultCallback
}
}
def delayedPrint(message: String, seconds: Long): Unit = {
println(s"Starting delay of $seconds seconds")
delaySeconds(seconds) {
println(message)
}
}
println("Delayed execution examples:")
delayedPrint("After 2 seconds", 2)
println("Main script continues")Make HTTP requests using HttpURLConnection or dispatch.
- GET:
new URL(url).openConnection().asInstanceOf[HttpURLConnection] - POST:
connection.setRequestMethod("POST") - Headers:
connection.setRequestProperty("User-Agent", "Scala") - Error handling:
try { ... } catch { ... }
// HTTP GET request
import java.net.HttpURLConnection
import java.io.{BufferedReader, InputStreamReader}
def fetchData(url: String): String = {
val connection = new java.net.URL(url).openConnection().asInstanceOf[HttpURLConnection]
connection.setRequestMethod("GET")
connection.setRequestProperty("User-Agent", "Scala")
try {
val reader = new BufferedReader(new InputStreamReader(connection.getInputStream))
val response = Iterator.continually(reader.readLine()).takeWhile(_ != null).mkString("
")
reader.close()
response
} catch {
case e: Exception =>
println(s"Error: ${e.getMessage}")
""
} finally {
connection.disconnect()
}
}
def postData(url: String, data: String): String = {
val connection = new java.net.URL(url).openConnection().asInstanceOf[HttpURLConnection]
connection.setRequestMethod("POST")
connection.setRequestProperty("Content-Type", "application/json")
connection.setDoOutput(true)
val writer = new java.io.PrintWriter(connection.getOutputStream)
writer.write(data)
writer.flush()
writer.close()
try {
val reader = new BufferedReader(new InputStreamReader(connection.getInputStream))
val response = Iterator.continually(reader.readLine()).takeWhile(_ != null).mkString("
")
reader.close()
response
} catch {
case e: Exception =>
println(s"Error: ${e.getMessage}")
""
} finally {
connection.disconnect()
}
}
// Example
val result = fetchData("https://api.github.com")
if (result.nonEmpty) {
println(result.take(500) + "...")
}Create promise-like behavior using Future and Promise.
- Promise:
Promise[String]() - Future:
promise.future - Complete:
promise.success(value),promise.failure(error) - Chain:
for { r1 <- p1; r2 <- p2 } yield (r1, r2)
// Create a promise-like task
import scala.concurrent.{Future, Promise}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
def createPromise(shouldResolve: Boolean): Future[String] = {
val promise = Promise[String]()
Future {
Thread.sleep(1000)
if (shouldResolve) {
promise.success("Success!")
} else {
promise.failure(new Exception("Failed!"))
}
}
promise.future
}
def chainPromises(p1: Future[String], p2: Future[String]): Future[(String, String)] = {
for {
result1 <- p1
_ <- Future(println(s"First: $result1"))
result2 <- p2
_ <- Future(println(s"Second: $result2"))
} yield (result1, result2)
}
// Example
val promise1 = createPromise(true)
val promise2 = createPromise(true)
chainPromises(promise1, promise2).onComplete {
case scala.util.Success((r1, r2)) =>
println(s"Both completed: $r1, $r2")
case scala.util.Failure(e) =>
println(s"Error: ${e.getMessage}")
}
// Wait for completion
Thread.sleep(3000)Calculate factorial using recursion or iteration.
- Recursive:
if (n <= 1) 1 else n * factorial(n - 1) - Iterative:
for (i <- 2 to n) { result *= i } - Tail recursive:
def fact(n: Int, acc: Int = 1): Int = if (n <= 1) acc else fact(n - 1, acc * n) - Edge cases: 0! = 1
// Factorial
def factorial(n: Int): Int = {
if (n <= 1) 1
else n * factorial(n - 1)
}
def factorialIterative(n: Int): Int = {
var result = 1
for (i <- 2 to n) {
result *= i
}
result
}
def factorialTail(n: Int, acc: Int = 1): Int = {
if (n <= 1) acc
else factorialTail(n - 1, acc * n)
}
val n = 5
println(s"Factorial of $n:")
println(s"Recursive: ${factorial(n)}")
println(s"Iterative: ${factorialIterative(n)}")
println(s"Tail recursive: ${factorialTail(n)}")Calculate Fibonacci numbers using recursion, iteration, or memoization.
- Recursive:
if (n <= 1) n else fib(n - 1) + fib(n - 2) - Iterative:
var a = 0; var b = 1; for (_ <- 2 to n) { val c = a + b; a = b; b = c } - Memoized:
val cache = mutable.Map.empty[Int, Int] - Time: O(n) iterative
// Fibonacci
def fibonacci(n: Int): Int = {
if (n <= 1) n
else fibonacci(n - 1) + fibonacci(n - 2)
}
def fibonacciIterative(n: Int): Int = {
if (n <= 1) n
else {
var a = 0
var b = 1
for (_ <- 2 to n) {
val c = a + b
a = b
b = c
}
b
}
}
def fibonacciMemoized(n: Int): Int = {
import scala.collection.mutable.Map
val cache = Map.empty[Int, Int]
def fib(n: Int): Int = {
if (n <= 1) n
else if (cache.contains(n)) cache(n)
else {
val result = fib(n - 1) + fib(n - 2)
cache(n) = result
result
}
}
fib(n)
}
val n = 10
println(s"Fibonacci of $n:")
println(s"Recursive: ${fibonacci(n)}")
println(s"Iterative: ${fibonacciIterative(n)}")
println(s"Memoized: ${fibonacciMemoized(n)}")Print numbers with FizzBuzz logic using conditional statements or pattern matching.
- If-else:
if (i % 15 == 0) "FizzBuzz" else if ... - Pattern matching:
(i % 3 == 0, i % 5 == 0) match { case (true, true) => ... } - List:
(1 to n).map(...) - Output:
println
// FizzBuzz
def fizzbuzz(n: Int): Unit = {
for (i <- 1 to n) {
if (i % 15 == 0) println("FizzBuzz")
else if (i % 3 == 0) println("Fizz")
else if (i % 5 == 0) println("Buzz")
else println(i)
}
}
def fizzbuzzList(n: Int): List[String] = {
(1 to n).map { i =>
if (i % 15 == 0) "FizzBuzz"
else if (i % 3 == 0) "Fizz"
else if (i % 5 == 0) "Buzz"
else i.toString
}.toList
}
def fizzbuzzMatch(n: Int): Unit = {
for (i <- 1 to n) {
(i % 3 == 0, i % 5 == 0) match {
case (true, true) => println("FizzBuzz")
case (true, false) => println("Fizz")
case (false, true) => println("Buzz")
case _ => println(i)
}
}
}
println("FizzBuzz for 15:")
fizzbuzz(15)
println("FizzBuzz list:")
println(fizzbuzzList(15).mkString(", "))Find missing number using sum formula or XOR operation.
- Sum:
n * (n + 1) / 2 - arr.sum - XOR:
xorAll ^ xorArr - Time: O(n)
- Edge cases: Empty array
// Find missing number
def findMissing(arr: Array[Int]): Int = {
val n = arr.length + 1
val total = n * (n + 1) / 2
val sum = arr.sum
total - sum
}
def findMissingXOR(arr: Array[Int]): Int = {
val n = arr.length + 1
var xorAll = 0
for (i <- 1 to n) {
xorAll ^= i
}
var xorArr = 0
for (value <- arr) {
xorArr ^= value
}
xorAll ^ xorArr
}
val arr = Array(1, 2, 4, 5, 6)
println(s"Missing number: ${findMissing(arr)}")
println(s"Missing number (XOR): ${findMissingXOR(arr)}")Find duplicates using groupBy, foldLeft, or manual tracking.
- groupBy:
list.groupBy(identity).collect { case (k, v) if v.size > 1 => k } - Manual:
var seen = Set.empty[T]; var duplicates = Set.empty[T] - Time: O(n)
- Returns: List of duplicates
// Find duplicates
def findDuplicates[T](list: List[T]): List[T] = {
list.groupBy(identity).collect { case (k, v) if v.size > 1 => k }.toList
}
def findDuplicatesManual[T](list: List[T]): List[T] = {
var seen = Set.empty[T]
var duplicates = Set.empty[T]
for (item <- list) {
if (seen.contains(item)) {
duplicates += item
} else {
seen += item
}
}
duplicates.toList
}
val list = List(1, 2, 3, 2, 4, 3, 5, 6, 5)
println(s"Original: ${list.mkString(", ")}")
println(s"Duplicates: ${findDuplicates(list).mkString(", ")}")
println(s"Duplicates (manual): ${findDuplicatesManual(list).mkString(", ")}")Sum array elements using sum, manual loop, or recursion.
- Built-in:
arr.sum - Manual:
var sum = 0; for (value <- arr) { sum += value } - Recursive:
if (index >= arr.length) 0 else arr(index) + sumRecursive(arr, index + 1) - Empty: Returns 0
// Sum of array
def sumArray(arr: Array[Int]): Int = arr.sum
def sumArrayManual(arr: Array[Int]): Int = {
var sum = 0
for (value <- arr) {
sum += value
}
sum
}
def sumArrayRecursive(arr: Array[Int], index: Int = 0): Int = {
if (index >= arr.length) 0
else arr(index) + sumArrayRecursive(arr, index + 1)
}
val arr = Array(1, 2, 3, 4, 5)
println(s"Array: ${arr.mkString(", ")}")
println(s"Sum: ${sumArray(arr)}")
println(s"Sum (manual): ${sumArrayManual(arr)}")
println(s"Sum (recursive): ${sumArrayRecursive(arr)}")Calculate average by dividing sum by length.
- Method:
arr.sum.toDouble / arr.length - Integer:
arr.sum / arr.length - Empty: Return 0
- Float: Returns double
// Average of array
def averageArray(arr: Array[Int]): Double = {
if (arr.isEmpty) 0.0
else arr.sum.toDouble / arr.length
}
def averageInteger(arr: Array[Int]): Int = {
if (arr.isEmpty) 0
else arr.sum / arr.length
}
val intArr = Array(1, 2, 3, 4, 5)
val floatArr = Array(1.0, 2.0, 3.0, 4.0, 5.0)
println(s"Average (int array): ${averageArray(intArr)}")
println(s"Average (float array): ${floatArr.sum / floatArr.length}")
println(s"Average (integer): ${averageInteger(intArr)}")Sort arrays using sorted or quickSort.
- Non-mutating:
arr.sorted - Mutating:
scala.util.Sorting.quickSort(arr) - Custom:
arr.sortWith(_ < _) - Time: O(n log n)
// Sort array ascending
def sortAscending[T: Ordering](arr: Array[T]): Array[T] = arr.sorted
def sortAscendingInPlace[T: Ordering](arr: Array[T]): Unit = {
scala.util.Sorting.quickSort(arr)
}
val arr = Array(5, 2, 8, 1, 9, 3)
println(s"Original: ${arr.mkString(", ")}")
val sorted = sortAscending(arr)
println(s"Sorted ascending: ${sorted.mkString(", ")}")
sortAscendingInPlace(arr)
println(s"Sorted in-place: ${arr.mkString(", ")}")Sort descending using sorted with reverse ordering.
- Non-mutating:
arr.sorted(Ordering[Int].reverse) - Mutating:
scala.util.Sorting.quickSort(arr)(Ordering[Int].reverse) - Custom:
arr.sortWith(_ > _) - Time: O(n log n)
// Sort array descending
def sortDescending[T: Ordering](arr: Array[T]): Array[T] = {
arr.sorted(Ordering[T].reverse)
}
def sortDescendingInPlace[T: Ordering](arr: Array[T]): Unit = {
scala.util.Sorting.quickSort(arr)(Ordering[T].reverse)
}
val arr = Array(5, 2, 8, 1, 9, 3)
println(s"Original: ${arr.mkString(", ")}")
val sorted = sortDescending(arr)
println(s"Sorted descending: ${sorted.mkString(", ")}")
sortDescendingInPlace(arr)
println(s"Sorted in-place: ${arr.mkString(", ")}")Flatten nested arrays using recursion or flatMap.
- Recursive:
def flatten(list: List[_]): List[_] = list.flatMap { case inner: List[_] => flatten(inner) case item => List(item) } - Iterative: Stack-based approach
- One level:
list.flatten - Depth: Handle arbitrary depth
// Flatten nested array
def flatten[T](list: List[T]): List[T] = {
list.flatMap {
case inner: List[_] => flatten(inner.asInstanceOf[List[T]])
case item => List(item)
}
}
def flattenIterative[T](list: List[T]): List[T] = {
var result = List.empty[T]
var stack = list.reverse
while (stack.nonEmpty) {
stack.head match {
case inner: List[_] =>
stack = inner.asInstanceOf[List[T]] ::: stack.tail
case item =>
result = item :: result
stack = stack.tail
}
}
result
}
val nested = List(List(1, 2), List(3, 4, 5), List(6), List(7, 8, 9, 10))
val deeper = List(List(1, 2), List(3, List(4, 5)))
println(s"Nested: ${nested.mkString(", ")}")
println(s"Flatten: ${flatten(nested).mkString(", ")}")
println(s"Deeper: ${deeper.mkString(", ")}")
println(s"Flatten deeper: ${flatten(deeper).mkString(", ")}")Split array into chunks using grouped or manual slicing.
- Built-in:
arr.grouped(size).toArray - Manual:
while (i < arr.length) { result += arr.slice(i, math.min(i + size, arr.length)); i += size } - Predicate:
chunkByPredicate - Use case: Batch processing
// Chunk array
def chunkArray[T](arr: Array[T], size: Int): Array[Array[T]] = {
arr.grouped(size).toArray
}
def chunkArrayManual[T](arr: Array[T], size: Int): Array[Array[T]] = {
val result = scala.collection.mutable.ArrayBuffer.empty[Array[T]]
var i = 0
while (i < arr.length) {
val end = math.min(i + size, arr.length)
result += arr.slice(i, end)
i += size
}
result.toArray
}
def chunkByPredicate[T](arr: Array[T], predicate: T => Boolean): Array[Array[T]] = {
val result = scala.collection.mutable.ArrayBuffer.empty[Array[T]]
var current = scala.collection.mutable.ArrayBuffer.empty[T]
for (item <- arr) {
if (predicate(item)) {
if (current.nonEmpty) {
result += current.toArray
current.clear()
}
result += Array(item)
} else {
current += item
}
}
if (current.nonEmpty) {
result += current.toArray
}
result.toArray
}
val arr = (1 to 10).toArray
println(s"Original: ${arr.mkString(", ")}")
println("Chunk (size 3):")
val chunks = chunkArray(arr, 3)
chunks.foreach(chunk => println(s"[${chunk.mkString(", ")}]"))Implement binary search using while loop or recursion.
- Iterative:
while (left <= right) { val mid = left + (right - left) / 2; ... } - Recursive:
def binarySearch(arr: Array[Int], target: Int, left: Int = 0, right: Int = arr.length - 1): Int - Time: O(log n)
- Precondition: Sorted array
// Binary search
def binarySearch[T: Ordering](arr: Array[T], target: T): Int = {
val ord = implicitly[Ordering[T]]
var left = 0
var right = arr.length - 1
while (left <= right) {
val mid = left + (right - left) / 2
val cmp = ord.compare(arr(mid), target)
if (cmp == 0) return mid
else if (cmp < 0) left = mid + 1
else right = mid - 1
}
-1
}
def binarySearchRecursive[T: Ordering](arr: Array[T], target: T, left: Int = 0, right: Int = -1): Int = {
val ord = implicitly[Ordering[T]]
val high = if (right < 0) arr.length - 1 else right
if (left > high) -1
else {
val mid = left + (high - left) / 2
val cmp = ord.compare(arr(mid), target)
if (cmp == 0) mid
else if (cmp < 0) binarySearchRecursive(arr, target, mid + 1, high)
else binarySearchRecursive(arr, target, left, mid - 1)
}
}
val arr = Array(1, 2, 3, 4, 5, 6, 7)
val target = 5
val index = binarySearch(arr, target)
println(s"Found $target at index: $index")
val target2 = 8
val index2 = binarySearch(arr, target2)
println(s"Found $target2 at index: $index2")Implement quick sort with partitioning and recursion.
- Recursive:
def quickSort(list: List[Int]): List[Int] = { if (list.length <= 1) list else { val pivot = list.head; val (left, right) = list.tail.partition(_ < pivot); quickSort(left) ::: pivot :: quickSort(right) } } - In-place:
quickSortInPlace - Pivot: First or last element
- Time: O(n log n) average
// Quick sort
def quickSort[T: Ordering](list: List[T]): List[T] = {
if (list.length <= 1) list
else {
val pivot = list.head
val (left, right) = list.tail.partition(_ < pivot)
quickSort(left) ::: pivot :: quickSort(right)
}
}
def quickSortInPlace[T: Ordering](arr: Array[T], low: Int = 0, high: Int = -1): Unit = {
val ord = implicitly[Ordering[T]]
val h = if (high < 0) arr.length - 1 else high
if (low < h) {
val pi = partition(arr, low, h)(ord)
quickSortInPlace(arr, low, pi - 1)
quickSortInPlace(arr, pi + 1, h)
}
}
def partition[T](arr: Array[T], low: Int, high: Int)(implicit ord: Ordering[T]): Int = {
val pivot = arr(high)
var i = low - 1
for (j <- low until high) {
if (ord.lteq(arr(j), pivot)) {
i += 1
val temp = arr(i)
arr(i) = arr(j)
arr(j) = temp
}
}
val temp = arr(i + 1)
arr(i + 1) = arr(high)
arr(high) = temp
i + 1
}
val list = List(5, 3, 8, 4, 2, 7, 1, 6)
val arr = Array(5, 3, 8, 4, 2, 7, 1, 6)
println(s"Original: ${list.mkString(", ")}")
println(s"Quick sort: ${quickSort(list).mkString(", ")}")
quickSortInPlace(arr)
println(s"Quick sort (in-place): ${arr.mkString(", ")}")Implement merge sort with divide and conquer approach.
- Divide:
val mid = list.length / 2; val (left, right) = list.splitAt(mid) - Merge:
def merge(left: List[Int], right: List[Int]): List[Int] = { (left, right) match { case (Nil, _) => right; case (_, Nil) => left; case (lh :: lt, rh :: rt) => if (lh < rh) lh :: merge(lt, right) else rh :: merge(left, rt) } } - Time: O(n log n)
// Merge sort
def mergeSort[T: Ordering](list: List[T]): List[T] = {
if (list.length <= 1) list
else {
val mid = list.length / 2
val (left, right) = list.splitAt(mid)
merge(mergeSort(left), mergeSort(right))
}
}
def merge[T: Ordering](left: List[T], right: List[T]): List[T] = {
val ord = implicitly[Ordering[T]]
def loop(l: List[T], r: List[T], acc: List[T]): List[T] = {
(l, r) match {
case (Nil, _) => acc.reverse ::: r
case (_, Nil) => acc.reverse ::: l
case (lh :: lt, rh :: rt) =>
if (ord.lteq(lh, rh)) loop(lt, r, lh :: acc)
else loop(l, rt, rh :: acc)
}
}
loop(left, right, Nil)
}
def mergeSortInPlace[T: Ordering](arr: Array[T], temp: Array[T], low: Int, high: Int): Unit = {
if (low < high) {
val mid = low + (high - low) / 2
mergeSortInPlace(arr, temp, low, mid)
mergeSortInPlace(arr, temp, mid + 1, high)
mergeInPlace(arr, temp, low, mid, high)
}
}
def mergeInPlace[T: Ordering](arr: Array[T], temp: Array[T], low: Int, mid: Int, high: Int): Unit = {
val ord = implicitly[Ordering[T]]
for (i <- low to high) {
temp(i) = arr(i)
}
var i = low
var j = mid + 1
var k = low
while (i <= mid && j <= high) {
if (ord.lteq(temp(i), temp(j))) {
arr(k) = temp(i)
i += 1
} else {
arr(k) = temp(j)
j += 1
}
k += 1
}
while (i <= mid) {
arr(k) = temp(i)
i += 1
k += 1
}
}
val list = List(5, 3, 8, 4, 2, 7, 1, 6)
println(s"Original: ${list.mkString(", ")}")
println(s"Merge sort: ${mergeSort(list).mkString(", ")}")Implement bubble sort with optimization to stop early if no swaps occur.
- Basic:
for (i <- 0 until n - 1) { for (j <- 0 until n - i - 1) { if (arr(j) > arr(j + 1)) { val temp = arr(j); arr(j) = arr(j + 1); arr(j + 1) = temp } } } - Optimized:
var swapped = false; for (j <- 0 until n - i - 1) { if (...) { ...; swapped = true } }; if (!swapped) return result - Time: O(n²) worst case
// Bubble sort
def bubbleSort[T: Ordering](arr: Array[T]): Array[T] = {
val result = arr.clone()
val n = result.length
for (i <- 0 until n - 1) {
for (j <- 0 until n - i - 1) {
if (implicitly[Ordering[T]].gt(result(j), result(j + 1))) {
val temp = result(j)
result(j) = result(j + 1)
result(j + 1) = temp
}
}
}
result
}
def bubbleSortOptimized[T: Ordering](arr: Array[T]): Array[T] = {
val ord = implicitly[Ordering[T]]
val result = arr.clone()
val n = result.length
for (i <- 0 until n - 1) {
var swapped = false
for (j <- 0 until n - i - 1) {
if (ord.gt(result(j), result(j + 1))) {
val temp = result(j)
result(j) = result(j + 1)
result(j + 1) = temp
swapped = true
}
}
if (!swapped) return result
}
result
}
val arr = Array(5, 3, 8, 4, 2, 7, 1, 6)
println(s"Original: ${arr.mkString(", ")}")
println(s"Bubble sort: ${bubbleSort(arr).mkString(", ")}")
println(s"Bubble sort optimized: ${bubbleSortOptimized(arr).mkString(", ")}")Find intersection using intersect or filter.
- Built-in:
arr1.intersect(arr2) - Filter:
arr1.filter(arr2.contains) - Set:
arr1.filter(arr2.toSet.contains) - Time: O(n*m) or O(n+m) with Set
// Intersection of arrays
def intersection[T](arr1: Array[T], arr2: Array[T]): Array[T] = {
arr1.intersect(arr2)
}
def intersectionManual[T](arr1: Array[T], arr2: Array[T]): Array[T] = {
arr1.filter(arr2.contains).distinct
}
def intersectionSet[T](arr1: Array[T], arr2: Array[T]): Array[T] = {
val set2 = arr2.toSet
arr1.filter(set2.contains).distinct
}
val arr1 = Array("apple", "banana", "orange", "grape", "kiwi")
val arr2 = Array("banana", "kiwi", "mango", "grape")
println(s"Intersection: ${intersection(arr1, arr2).mkString(", ")}")
println(s"Intersection (manual): ${intersectionManual(arr1, arr2).mkString(", ")}")
val ints1 = Array(1, 2, 3, 4, 5)
val ints2 = Array(4, 5, 6, 7, 8)
println(s"Intersection (ints): ${intersection(ints1, ints2).mkString(", ")}")Union arrays using distinct or manual merge.
- Built-in:
(arr1 ++ arr2).distinct - Manual:
val result = ArrayBuffer.empty[T]; result ++= arr1; for (item <- arr2) { if (!result.contains(item)) result += item } - Time: O(n+m)
// Union of arrays
def union[T](arr1: Array[T], arr2: Array[T]): Array[T] = {
(arr1 ++ arr2).distinct
}
def unionManual[T](arr1: Array[T], arr2: Array[T]): Array[T] = {
val result = scala.collection.mutable.ArrayBuffer.empty[T]
result ++= arr1
for (item <- arr2) {
if (!result.contains(item)) {
result += item
}
}
result.toArray
}
val arr1 = Array("apple", "banana", "orange")
val arr2 = Array("orange", "grape", "kiwi")
println(s"Union: ${union(arr1, arr2).mkString(", ")}")
println(s"Union (manual): ${unionManual(arr1, arr2).mkString(", ")}")
val ints1 = Array(1, 2, 3, 4)
val ints2 = Array(4, 5, 6, 7)
println(s"Union (ints): ${union(ints1, ints2).mkString(", ")}")Find difference using filterNot or diff.
- Difference:
arr1.filterNot(arr2.contains) - Symmetric:
val diff1 = arr1.filterNot(arr2.contains); val diff2 = arr2.filterNot(arr1.contains); diff1 ++ diff2 - Time: O(n*m)
// Difference of arrays
def difference[T](arr1: Array[T], arr2: Array[T]): Array[T] = {
arr1.filterNot(arr2.contains)
}
def symmetricDifference[T](arr1: Array[T], arr2: Array[T]): Array[T] = {
val diff1 = arr1.filterNot(arr2.contains)
val diff2 = arr2.filterNot(arr1.contains)
diff1 ++ diff2
}
val arr1 = Array("apple", "banana", "orange", "grape")
val arr2 = Array("banana", "kiwi", "grape")
println(s"Difference: ${difference(arr1, arr2).mkString(", ")}")
println(s"Symmetric difference: ${symmetricDifference(arr1, arr2).mkString(", ")}")
val ints1 = Array(1, 2, 3, 4, 5)
val ints2 = Array(4, 5, 6, 7, 8)
println(s"Difference (ints): ${difference(ints1, ints2).mkString(", ")}")Group objects by property using groupBy.
- Method:
list.groupBy(keyExtractor) - Count:
list.groupBy(keyExtractor).mapValues(_.size) - Sum:
list.groupBy(keyExtractor).mapValues(_.map(valueExtractor).sum) - Use case: Data aggregation
// Group by property
case class Person(name: String, age: Int, city: String)
def groupBy[A, K](list: List[A], keyExtractor: A => K): Map[K, List[A]] = {
list.groupBy(keyExtractor)
}
def groupAndCount[A, K](list: List[A], keyExtractor: A => K): Map[K, Int] = {
list.groupBy(keyExtractor).mapValues(_.size)
}
def groupAndSum[A, K, V](list: List[A], keyExtractor: A => K, valueExtractor: A => V)(implicit num: Numeric[V]): Map[K, V] = {
list.groupBy(keyExtractor).mapValues(_.map(valueExtractor).sum)
}
val people = List(
Person("Alice", 25, "NYC"),
Person("Bob", 30, "LA"),
Person("Charlie", 25, "NYC"),
Person("David", 35, "Chicago"),
Person("Eve", 30, "LA")
)
println("Group by age:")
val byAge = groupBy(people, (p: Person) => p.age)
byAge.foreach { case (age, persons) =>
println(s"Age $age: ${persons.map(_.name).mkString(", ")}")
}
println("Group by city:")
val byCity = groupBy(people, (p: Person) => p.city)
byCity.foreach { case (city, persons) =>
println(s"City $city: ${persons.map(_.name).mkString(", ")}")
}
println("Count by age:")
println(groupAndCount(people, (p: Person) => p.age))Create deep copies using recursion to clone nested structures.
- Method:
def deepClone[T](obj: T): T = { obj match { case list: List[_] => list.map(deepClone).asInstanceOf[T]; case map: Map[_, _] => map.map { case (k, v) => (deepClone(k), deepClone(v)) }.asInstanceOf[T]; case _ => obj } } - Case classes:
copymethod - Limitations: Handles common types
// Deep clone object
def deepClone[T](obj: T): T = {
obj match {
case list: List[_] =>
list.map(deepClone).asInstanceOf[T]
case map: Map[_, _] =>
map.map { case (k, v) => (deepClone(k), deepClone(v)) }.asInstanceOf[T]
case seq: Seq[_] =>
seq.map(deepClone).asInstanceOf[T]
case array: Array[_] =>
array.map(deepClone).asInstanceOf[T]
case option: Option[_] =>
option.map(deepClone).asInstanceOf[T]
case _ => obj
}
}
case class Address(street: String, city: String)
case class Person(name: String, age: Int, address: Address)
val original = Person("Alice", 25, Address("123 Main St", "NYC"))
val cloned = deepClone(original)
cloned.address = original.address.copy(street = "456 Oak St")
println(s"Original: ${original.address.street}")
println(s"Cloned: ${cloned.address.street}")Perform immutable updates using path-based updates.
- Method:
def updateImmutable(obj: Map[String, Any], path: String, value: Any): Map[String, Any] - Path: Dot notation
- Recursive: Helper function
- Use case: State management
// Immutable update
def updateImmutable[T](obj: Map[String, Any], path: String, value: Any): Map[String, Any] = {
val parts = path.split("\.")
if (parts.length == 1) {
obj + (parts.head -> value)
} else {
val first = parts.head
val rest = parts.tail.mkString(".")
val updated = obj.get(first) match {
case Some(inner: Map[_, _]) =>
updateImmutable(inner.asInstanceOf[Map[String, Any]], rest, value)
case _ =>
updateImmutable(Map.empty[String, Any], rest, value)
}
obj + (first -> updated)
}
}
val state = Map("user" -> Map("name" -> "Alice", "age" -> 25))
val newState = updateImmutable(state, "user.age", 26)
println(s"Original: ${state("user")("age")}")
println(s"Updated: ${newState("user")("age")}")Implement pipe for left-to-right function composition.
- Method:
def pipe[T](value: T, fns: (T => T)*): T = fns.foldLeft(value)((acc, fn) => fn(acc)) - Compose:
def compose[T](fns: (T => T)*): T => T = fns.reduceLeft((f, g) => x => g(f(x))) - Use case: Function chaining
// Pipe function
def pipe[T](value: T, fns: (T => T)*): T = {
fns.foldLeft(value)((acc, fn) => fn(acc))
}
def compose[T](fns: (T => T)*): T => T = {
fns.reduceLeft((f, g) => x => g(f(x)))
}
val double: Int => Int = _ * 2
val addTen: Int => Int = _ + 10
val square: Int => Int = x => x * x
val result = pipe(5, double, addTen, square)
println(s"Pipe: $result")
val process = compose(double, addTen, square)
println(s"Compose: ${process(5)}")Implement compose for right-to-left function composition.
- Method:
def composeAlt[T](fns: (T => T)*): T => T = fns.reduceRight((f, g) => x => f(g(x))) - With logging:
composeWithLogging - Direction: Right to left
// Compose function
def composeAlt[T](fns: (T => T)*): T => T = {
fns.reduceRight((f, g) => x => f(g(x)))
}
def composeWithLogging[T](fns: (T => T)*): T => T = {
fns.reduceRight { (f, g) =>
x => {
val result = f(g(x))
println(s"Intermediate: $result")
result
}
}
}
val double: Int => Int = _ * 2
val addTen: Int => Int = _ + 10
val square: Int => Int = x => x * x
val composed = composeAlt(double, addTen, square)
println(s"Composed: ${composed(5)}")
val composedWithLogging = composeWithLogging(double, addTen, square)
println(s"Composed with logging: ${composedWithLogging(5)}")Implement memoization using mutable Map cache.
- Method:
def memoize[T, R](fn: T => R): T => R = { val cache = mutable.Map.empty[T, R]; (arg: T) => cache.getOrElseUpdate(arg, fn(arg)) } - Multiple args:
memoizeMultiple - Use case: Expensive functions
// Memoization
def memoize[T, R](fn: T => R): T => R = {
val cache = scala.collection.mutable.Map.empty[T, R]
(arg: T) => {
cache.getOrElseUpdate(arg, fn(arg))
}
}
def memoizeMultiple[T, R](fn: T => R): T => R = {
val cache = scala.collection.mutable.Map.empty[T, R]
(arg: T) => {
if (cache.contains(arg)) cache(arg)
else {
val result = fn(arg)
cache(arg) = result
result
}
}
}
// Fibonacci with memoization
val fib: Int => Int = memoize { n =>
if (n <= 1) n
else fib(n - 1) + fib(n - 2)
}
val start = System.currentTimeMillis()
println(s"Fibonacci(35): ${fib(35)}")
val time1 = System.currentTimeMillis() - start
println(s"Time: ${time1}ms")
val start2 = System.currentTimeMillis()
println(s"Fibonacci(35) again: ${fib(35)}")
val time2 = System.currentTimeMillis() - start2
println(s"Time: ${time2}ms")Implement once function that ensures a function is called only once.
- Method:
def once[T, R](fn: T => R): T => R = { var called = false; var result: Option[R] = None; (arg: T) => { if (!called) { called = true; result = Some(fn(arg)) }; result.get } } - With reset:
onceWithReset
// Once function
def once[T, R](fn: T => R): T => R = {
var called = false
var result: Option[R] = None
(arg: T) => {
if (!called) {
called = true
result = Some(fn(arg))
}
result.get
}
}
def onceWithReset[T, R](fn: T => R): (T => R, () => Unit) = {
var called = false
var result: Option[R] = None
val reset = () => {
called = false
result = None
}
val fnOnce = (arg: T) => {
if (!called) {
called = true
result = Some(fn(arg))
}
result.get
}
(fnOnce, reset)
}
val initialize = once { (value: Int) =>
println(s"Initialized with $value")
value * 2
}
println(s"First call: ${initialize(10)}")
println(s"Second call: ${initialize(20)}")
val (init, reset) = onceWithReset { (value: Int) =>
println(s"Initialized with $value")
value * 2
}
println(s"First with reset: ${init(10)}")
reset()
println(s"After reset: ${init(20)}")Implement debounce with leading edge execution.
- Method:
def debounceLeading[T](fn: T => Unit, delay: Long): T => Unit = { var lastCall = 0L; var timeout: Option[Thread] = None; (arg: T) => { val now = System.currentTimeMillis(); if (now - lastCall >= delay) { lastCall = now; fn(arg) } else { if (timeout.isEmpty) { val thread = new Thread { override def run(): Unit = { Thread.sleep(delay - (now - lastCall)); timeout = None; lastCall = System.currentTimeMillis(); fn(arg) } }; timeout = Some(thread); thread.start() } } } } - Use case: Search inputs
// Debounce with leading edge
def debounceLeading[T](fn: T => Unit, delay: Long): T => Unit = {
var lastCall = 0L
var timeout: Option[Thread] = None
(arg: T) => {
val now = System.currentTimeMillis()
if (now - lastCall >= delay) {
lastCall = now
fn(arg)
} else {
if (timeout.isEmpty) {
val thread = new Thread {
override def run(): Unit = {
Thread.sleep(delay - (now - lastCall))
timeout = None
lastCall = System.currentTimeMillis()
fn(arg)
}
}
timeout = Some(thread)
thread.start()
}
}
}
}
def debounceSimple[T](fn: T => Unit, delay: Long): T => Unit = {
var lastCall = 0L
(arg: T) => {
val now = System.currentTimeMillis()
if (now - lastCall >= delay) {
lastCall = now
fn(arg)
}
}
}
val debounced = debounceSimple { (value: Int) =>
println(s"Processing: $value")
} (2000)
println(debounced(1))
println(debounced(2))
Thread.sleep(3000)
println(debounced(3))Implement throttle with leading edge execution.
- Method:
def throttleLeading[T](fn: T => Unit, delay: Long): T => Unit = { var lastCall = 0L; (arg: T) => { val now = System.currentTimeMillis(); if (now - lastCall >= delay) { lastCall = now; fn(arg) } } } - With trailing:
throttleWithTrailing - Use case: Scroll events
// Throttle with leading edge
def throttleLeading[T](fn: T => Unit, delay: Long): T => Unit = {
var lastCall = 0L
(arg: T) => {
val now = System.currentTimeMillis()
if (now - lastCall >= delay) {
lastCall = now
fn(arg)
}
}
}
def throttleWithTrailing[T](fn: T => Unit, delay: Long): T => Unit = {
var lastCall = 0L
var pending: Option[T] = None
var timer: Option[Thread] = None
(arg: T) => {
val now = System.currentTimeMillis()
if (now - lastCall >= delay) {
lastCall = now
fn(arg)
} else {
pending = Some(arg)
if (timer.isEmpty) {
val remaining = delay - (now - lastCall)
val thread = new Thread {
override def run(): Unit = {
Thread.sleep(remaining)
timer = None
lastCall = System.currentTimeMillis()
pending.foreach(fn)
pending = None
}
}
timer = Some(thread)
thread.start()
}
}
}
}
val throttled = throttleLeading { (value: Int) =>
println(s"Processing: $value")
} (2000)
println(throttled(1))
println(throttled(2))
Thread.sleep(3000)
println(throttled(3))Implement deep equality comparison for nested structures.
- Method:
def deepEqual(a: Any, b: Any): Boolean = { (a, b) match { case (a: List[_], b: List[_]) => a.length == b.length && a.zip(b).forall { case (x, y) => deepEqual(x, y) }; case (a: Map[_, _], b: Map[_, _]) => a.size == b.size && a.forall { case (k, v) => b.get(k).exists(deepEqual(v, _)) }; case (a: Product, b: Product) => a.productArity == b.productArity && a.productIterator.zip(b.productIterator).forall { case (x, y) => deepEqual(x, y) }; case _ => a == b } }
// Deep equal
def deepEqual(a: Any, b: Any): Boolean = {
(a, b) match {
case (a: List[_], b: List[_]) =>
a.length == b.length && a.zip(b).forall { case (x, y) => deepEqual(x, y) }
case (a: Map[_, _], b: Map[_, _]) =>
a.size == b.size && a.forall { case (k, v) =>
b.get(k).exists(deepEqual(v, _))
}
case (a: Array[_], b: Array[_]) =>
a.length == b.length && a.zip(b).forall { case (x, y) => deepEqual(x, y) }
case (a: Option[_], b: Option[_]) =>
(a, b) match {
case (Some(x), Some(y)) => deepEqual(x, y)
case (None, None) => true
case _ => false
}
case (a: Product, b: Product) =>
a.productArity == b.productArity &&
a.productIterator.zip(b.productIterator).forall { case (x, y) => deepEqual(x, y) }
case _ => a == b
}
}
case class Person(name: String, age: Int)
case class Address(street: String, city: String)
val obj1 = Person("Alice", 25)
val obj2 = Person("Alice", 25)
val obj3 = Person("Alice", 26)
println(s"obj1 == obj2: ${deepEqual(obj1, obj2)}")
println(s"obj1 == obj3: ${deepEqual(obj1, obj3)}")Implement observable pattern with subscribers and notification.
- Observable:
class Observable[T] { private val subscribers = mutable.ListBuffer.empty[T => Unit]; def subscribe(callback: T => Unit): () => Unit = { subscribers += callback; () => subscribers -= callback }; def notify(data: T): Unit = { subscribers.foreach(_(data)) } } - Stateful:
StatefulObservable
// Observable pattern
import scala.collection.mutable
class Observable[T] {
private val subscribers = mutable.ListBuffer.empty[T => Unit]
def subscribe(callback: T => Unit): () => Unit = {
subscribers += callback
() => subscribers -= callback
}
def notify(data: T): Unit = {
subscribers.foreach(_(data))
}
}
class StatefulObservable[T](initialState: T) {
private var state = initialState
private val observable = new Observable[T]
def subscribe(callback: T => Unit): () => Unit = observable.subscribe(callback)
def setState(newState: T): Unit = {
state = newState
observable.notify(state)
}
def getState: T = state
}
// Usage
val observable = new Observable[String]
val id1 = observable.subscribe(data => println(s"Observer1: $data"))
val id2 = observable.subscribe(data => println(s"Observer2: $data"))
println("Notifying observers:")
observable.notify("Hello, World!")
id1()
println("After unsubscribing observer1:")
observable.notify("Hello again!")
val stateful = new StatefulObservable(0)
stateful.subscribe(state => println(s"State changed to: $state"))
println(s"Current state: ${stateful.getState}")
stateful.setState(10)
stateful.setState(20)Implement singleton pattern using companion object or lazy val.
- Companion object:
object Singleton { private var instance: Option[Singleton] = None; def getInstance: Singleton = { instance.getOrElse { val newInstance = new Singleton(); instance = Some(newInstance); newInstance } } } - Lazy val:
object LazySingleton { lazy val instance = new LazySingleton() }
// Singleton pattern
object Singleton {
private var instance: Option[Singleton] = None
def getInstance: Singleton = {
instance.getOrElse {
val newInstance = new Singleton()
instance = Some(newInstance)
newInstance
}
}
def reset(): Unit = {
instance = None
}
}
class Singleton private() {
private val data = scala.collection.mutable.Map.empty[String, Any]
def set(key: String, value: Any): Unit = {
data(key) = value
}
def get(key: String): Option[Any] = data.get(key)
}
// Alternative singleton using lazy val
object LazySingleton {
lazy val instance = new LazySingleton()
}
class LazySingleton private() {
private val data = scala.collection.mutable.Map.empty[String, Any]
def set(key: String, value: Any): Unit = {
data(key) = value
}
def get(key: String): Option[Any] = data.get(key)
}
// Usage
val singleton1 = Singleton.getInstance
val singleton2 = Singleton.getInstance
println(s"singleton1 == singleton2: ${singleton1 == singleton2}")
singleton1.set("key", "value")
println(s"singleton2 get: ${singleton2.get("key")}")Implement factory pattern for creating objects without specifying concrete classes.
- Factory:
object UserFactory { def create(userType: String, name: String): User = { userType match { case "admin" => Admin(name); case "guest" => Guest(name); case _ => RegularUser(name) } } }
// Factory pattern
trait User {
def name: String
def userType: String
}
case class Admin(name: String) extends User {
def userType: String = "admin"
}
case class Guest(name: String) extends User {
def userType: String = "guest"
}
case class RegularUser(name: String) extends User {
def userType: String = "regular"
}
object UserFactory {
def create(userType: String, name: String): User = {
userType match {
case "admin" => Admin(name)
case "guest" => Guest(name)
case _ => RegularUser(name)
}
}
def createAdmin(name: String): Admin = Admin(name)
def createGuest(name: String): Guest = Guest(name)
def createRegular(name: String): RegularUser = RegularUser(name)
}
// Usage
val user1 = UserFactory.create("admin", "Alice")
val user2 = UserFactory.create("guest", "Bob")
val user3 = UserFactory.create("regular", "Charlie")
println(s"${user1.name} is ${user1.userType}")
println(s"${user2.name} is ${user2.userType}")
println(s"${user3.name} is ${user3.userType}")Implement strategy pattern with interchangeable strategies.
- Strategy:
trait PaymentStrategy { def pay(amount: Double): Unit } - Context:
class PaymentContext(var strategy: PaymentStrategy) { def executePayment(amount: Double): Unit = strategy.pay(amount) } - Decorator:
DiscountDecorator
// Strategy pattern
trait PaymentStrategy {
def pay(amount: Double): Unit
}
class CreditCardStrategy extends PaymentStrategy {
def pay(amount: Double): Unit = {
println(s"Paid $$amount with Credit Card")
}
}
class PayPalStrategy extends PaymentStrategy {
def pay(amount: Double): Unit = {
println(s"Paid $$amount with PayPal")
}
}
class CryptoStrategy extends PaymentStrategy {
def pay(amount: Double): Unit = {
println(s"Paid $$amount with Crypto")
}
}
class PaymentContext(var strategy: PaymentStrategy) {
def setStrategy(strategy: PaymentStrategy): Unit = {
this.strategy = strategy
}
def executePayment(amount: Double): Unit = {
strategy.pay(amount)
}
}
// Usage
val context = new PaymentContext(new CreditCardStrategy)
context.executePayment(100.0)
context.setStrategy(new PayPalStrategy)
context.executePayment(50.0)
context.setStrategy(new CryptoStrategy)
context.executePayment(75.0)
// With discount decorator
class DiscountDecorator(strategy: PaymentStrategy, discount: Double) extends PaymentStrategy {
def pay(amount: Double): Unit = {
val discounted = amount * (1 - discount)
println(s"Applied discount of ${discount * 100}%")
strategy.pay(discounted)
}
}
val discounted = new DiscountDecorator(new PayPalStrategy, 0.1)
discounted.pay(100.0)Implement observer pattern with subject and observers.
- Subject:
class ConcreteSubject extends Subject { private val observers = mutable.ListBuffer.empty[Observer]; private var state: Any = _; def attach(observer: Observer): Unit = observers += observer; def setState(state: Any): Unit = { this.state = state; notifyObservers() } } - Observer:
class ConcreteObserver(name: String) extends Observer { def update(data: Any): Unit = println(s"Observer $name received: $data") }
// Observer pattern
trait Observer {
def update(data: Any): Unit
}
trait Subject {
def attach(observer: Observer): Unit
def detach(observer: Observer): Unit
def notifyObservers(): Unit
}
class ConcreteSubject extends Subject {
private val observers = scala.collection.mutable.ListBuffer.empty[Observer]
private var state: Any = _
def attach(observer: Observer): Unit = observers += observer
def detach(observer: Observer): Unit = observers -= observer
def notifyObservers(): Unit = {
observers.foreach(_.update(state))
}
def setState(state: Any): Unit = {
this.state = state
notifyObservers()
}
def getState: Any = state
}
class ConcreteObserver(name: String) extends Observer {
def update(data: Any): Unit = {
println(s"Observer $name received: $data")
}
}
class DerivedObserver(name: String, transform: Any => Any) extends Observer {
def update(data: Any): Unit = {
val transformed = transform(data)
println(s"Derived observer $name: $transformed")
}
}
// Usage
val subject = new ConcreteSubject
val observer1 = new ConcreteObserver("1")
val observer2 = new ConcreteObserver("2")
val observer3 = new DerivedObserver("3", (data: Any) => data.toString.toUpperCase)
subject.attach(observer1)
subject.attach(observer2)
subject.attach(observer3)
println("Setting state:")
subject.setState("Hello, World!")
subject.setState("Another update")
subject.detach(observer1)
println("After detaching observer1:")
subject.setState("Final state")Implement decorator pattern for adding features.
- Component:
trait Coffee { def getCost(): Double; def getDescription(): String } - Decorator:
abstract class CoffeeDecorator(val coffee: Coffee) extends Coffee - Concrete:
class MilkDecorator(coffee: Coffee) extends CoffeeDecorator(coffee) { override def getCost(): Double = coffee.getCost() + 2.0 }
// Decorator pattern
trait Coffee {
def getCost(): Double
def getDescription(): String
}
class BasicCoffee extends Coffee {
def getCost(): Double = 5.0
def getDescription(): String = "Coffee"
}
abstract class CoffeeDecorator(val coffee: Coffee) extends Coffee {
def getCost(): Double = coffee.getCost()
def getDescription(): String = coffee.getDescription()
}
class MilkDecorator(coffee: Coffee) extends CoffeeDecorator(coffee) {
override def getCost(): Double = coffee.getCost() + 2.0
override def getDescription(): String = coffee.getDescription() + ", Milk"
}
class SugarDecorator(coffee: Coffee) extends CoffeeDecorator(coffee) {
override def getCost(): Double = coffee.getCost() + 1.0
override def getDescription(): String = coffee.getDescription() + ", Sugar"
}
class CaramelDecorator(coffee: Coffee) extends CoffeeDecorator(coffee) {
override def getCost(): Double = coffee.getCost() + 2.5
override def getDescription(): String = coffee.getDescription() + ", Caramel"
}
class WhippedCreamDecorator(coffee: Coffee) extends CoffeeDecorator(coffee) {
override def getCost(): Double = coffee.getCost() + 1.5
override def getDescription(): String = coffee.getDescription() + ", Whipped Cream"
}
// Usage
val coffee = new BasicCoffee
println(s"${coffee.getDescription()} ($$${coffee.getCost()})")
val withMilk = new MilkDecorator(coffee)
println(s"${withMilk.getDescription()} ($$${withMilk.getCost()})")
val withSugar = new SugarDecorator(coffee)
println(s"${withSugar.getDescription()} ($$${withSugar.getCost()})")
val withMilkSugar = new SugarDecorator(new MilkDecorator(coffee))
println(s"${withMilkSugar.getDescription()} ($$${withMilkSugar.getCost()})")
val fullyDecorated = new CaramelDecorator(
new WhippedCreamDecorator(
new SugarDecorator(
new MilkDecorator(coffee)
)
)
)
println(s"${fullyDecorated.getDescription()} ($$${fullyDecorated.getCost()})")Implement command pattern with execute, undo, and redo.
- Command:
class AddCommand(var receiver: Int, value: Int) extends Command { def execute(): Unit = { oldValue = receiver; receiver += value }; def undo(): Unit = { receiver = oldValue } } - History:
class CommandHistory { private val history = mutable.ListBuffer.empty[Command]; private var current = 0; def execute(command: Command): Unit = { command.execute(); history.trimEnd(history.length - current); history += command; current += 1 } }
// Command pattern
trait Command {
def execute(): Unit
def undo(): Unit
def redo(): Unit
}
class AddCommand(var receiver: Int, value: Int) extends Command {
private var oldValue = receiver
def execute(): Unit = {
oldValue = receiver
receiver += value
}
def undo(): Unit = {
receiver = oldValue
}
def redo(): Unit = {
execute()
}
}
class SubtractCommand(var receiver: Int, value: Int) extends Command {
private var oldValue = receiver
def execute(): Unit = {
oldValue = receiver
receiver -= value
}
def undo(): Unit = {
receiver = oldValue
}
def redo(): Unit = {
execute()
}
}
class MacroCommand(commands: Command*) extends Command {
def execute(): Unit = commands.foreach(_.execute())
def undo(): Unit = commands.reverse.foreach(_.undo())
def redo(): Unit = commands.foreach(_.redo())
}
class CommandHistory {
private val history = scala.collection.mutable.ListBuffer.empty[Command]
private var current = 0
def execute(command: Command): Unit = {
command.execute()
history.trimEnd(history.length - current)
history += command
current += 1
}
def undo(): Boolean = {
if (current > 0) {
current -= 1
history(current).undo()
true
} else false
}
def redo(): Boolean = {
if (current < history.length) {
history(current).redo()
current += 1
true
} else false
}
}
// Usage
var counter = 0
val history = new CommandHistory
val add5 = new AddCommand(counter, 5)
val sub3 = new SubtractCommand(counter, 3)
println(s"Initial: $counter")
history.execute(add5)
println(s"After add: $counter")
history.execute(sub3)
println(s"After sub: $counter")
history.undo()
println(s"After undo: $counter")
history.redo()
println(s"After redo: $counter")
val macroCmd = new MacroCommand(add5, add5, sub3)
history.execute(macroCmd)
println(s"After macro: $counter")Implement memento pattern for state capture and restoration.
- Memento:
class Memento(val state: Map[String, Any]) - Originator:
class Originator { private var state: Map[String, Any] = Map.empty; def save(): Memento = new Memento(state); def restore(memento: Memento): Unit = { state = memento.state } } - Caretaker:
class Caretaker { private val mementos = mutable.ListBuffer.empty[Memento]; private var current = 0; def save(memento: Memento): Unit = { mementos.trimEnd(mementos.length - current); mementos += memento; current += 1 } }
// Memento pattern
class Memento(val state: Map[String, Any])
class Originator {
private var state: Map[String, Any] = Map.empty
def save(): Memento = new Memento(state)
def restore(memento: Memento): Unit = {
state = memento.state
}
def setState(state: Map[String, Any]): Unit = {
this.state = state
}
def getState: Map[String, Any] = state
}
class Caretaker {
private val mementos = scala.collection.mutable.ListBuffer.empty[Memento]
private var current = 0
def save(memento: Memento): Unit = {
mementos.trimEnd(mementos.length - current)
mementos += memento
current += 1
}
def undo(): Option[Memento] = {
if (current > 0) {
current -= 1
Some(mementos(current))
} else None
}
def redo(): Option[Memento] = {
if (current < mementos.length) {
val memento = mementos(current)
current += 1
Some(memento)
} else None
}
}
// Usage
val originator = new Originator
val caretaker = new Caretaker
caretaker.save(originator.save())
originator.setState(Map("value" -> 1))
caretaker.save(originator.save())
originator.setState(Map("value" -> 2))
caretaker.save(originator.save())
originator.setState(Map("value" -> 3))
println(s"Current: ${originator.getState("value")}")
caretaker.undo().foreach { memento =>
originator.restore(memento)
println(s"After undo: ${originator.getState("value")}")
}
caretaker.redo().foreach { memento =>
originator.restore(memento)
println(s"After redo: ${originator.getState("value")}")
}Implement mediator pattern for centralized communication.
- Mediator:
class ConcreteMediator extends Mediator { private val colleagues = mutable.ListBuffer.empty[Colleague]; def register(colleague: Colleague): Unit = { colleagues += colleague; colleague.setMediator(this) }; def send(message: String, sender: Colleague): Unit = { colleagues.filter(_ != sender).foreach(_.receive(message)) } }
// Mediator pattern
trait Mediator {
def send(message: String, sender: Colleague): Unit
def register(colleague: Colleague): Unit
}
abstract class Colleague(val name: String) {
private var mediator: Mediator = _
def setMediator(mediator: Mediator): Unit = {
this.mediator = mediator
}
def send(message: String): Unit = {
mediator.send(message, this)
}
def receive(message: String): Unit = {
println(s"$name received: $message")
}
}
class ConcreteMediator extends Mediator {
private val colleagues = scala.collection.mutable.ListBuffer.empty[Colleague]
def register(colleague: Colleague): Unit = {
colleagues += colleague
colleague.setMediator(this)
}
def send(message: String, sender: Colleague): Unit = {
colleagues.filter(_ != sender).foreach(_.receive(message))
}
}
class StatefulColleague(name: String, var state: Int) extends Colleague(name) {
override def receive(message: String): Unit = {
println(s"$name (state $state) received: $message")
}
def setState(state: Int): Unit = {
this.state = state
}
}
// Usage
val mediator = new ConcreteMediator
val alice = new Colleague("Alice")
val bob = new Colleague("Bob")
val charlie = new Colleague("Charlie")
mediator.register(alice)
mediator.register(bob)
mediator.register(charlie)
println("Sending messages:")
alice.send("Hello everyone!")
bob.send("Meeting at 3pm")
val mediator2 = new ConcreteMediator
val alice2 = new StatefulColleague("Alice", 0)
val bob2 = new StatefulColleague("Bob", 1)
mediator2.register(alice2)
mediator2.register(bob2)
alice2.send("Custom message for stateful colleagues")Implement chain of responsibility with linked handlers.
- Handler:
abstract class Handler { private var nextHandler: Option[Handler] = None; def setNext(handler: Handler): Handler = { nextHandler = Some(handler); handler }; def handle(request: Map[String, Any]): Boolean = { nextHandler.exists(_.handle(request)) || true } }
// Chain of Responsibility
abstract class Handler {
private var nextHandler: Option[Handler] = None
def setNext(handler: Handler): Handler = {
nextHandler = Some(handler)
handler
}
def handle(request: Map[String, Any]): Boolean = {
nextHandler.exists(_.handle(request)) || true
}
}
class AuthHandler extends Handler {
override def handle(request: Map[String, Any]): Boolean = {
if (request.contains("token")) {
println("Authentication passed")
super.handle(request)
} else {
println("Authentication failed")
false
}
}
}
class LoggerHandler extends Handler {
override def handle(request: Map[String, Any]): Boolean = {
val url = request.getOrElse("url", "unknown")
println(s"Logging request: $url")
super.handle(request)
}
}
class ValidationHandler extends Handler {
override def handle(request: Map[String, Any]): Boolean = {
if (request.contains("data")) {
println("Validation passed")
super.handle(request)
} else {
println("Validation failed")
false
}
}
}
class RateLimitHandler extends Handler {
private var lastCall = 0L
private val limit = 5000L // 5 seconds
override def handle(request: Map[String, Any]): Boolean = {
val now = System.currentTimeMillis()
if (now - lastCall >= limit) {
lastCall = now
println("Rate limit passed")
super.handle(request)
} else {
println("Rate limit exceeded")
false
}
}
}
// Usage
val auth = new AuthHandler
val logger = new LoggerHandler
val validator = new ValidationHandler
val rateLimiter = new RateLimitHandler
auth.setNext(logger).setNext(validator).setNext(rateLimiter)
val request = Map("token" -> "valid", "url" -> "/api", "data" -> "payload")
println("Processing valid request:")
auth.handle(request)
val request2 = Map("url" -> "/public")
println("Processing invalid request:")
auth.handle(request2)Implement state pattern with context and state transitions.
- Context:
class Context { private var state: State = new ReadyState; def setState(state: State): Unit = { this.state = state }; def request(): Unit = { state.handle(this) } } - States:
class ReadyState extends State { def handle(context: Context): Unit = { println("Ready"); context.setState(new ProcessingState) } }
// State pattern
trait State {
def handle(context: Context): Unit
}
class ReadyState extends State {
def handle(context: Context): Unit = {
println("Ready: Waiting for input")
context.setState(new ProcessingState)
}
}
class ProcessingState extends State {
def handle(context: Context): Unit = {
println("Processing: Working on task")
context.setState(new CompletedState)
}
}
class CompletedState extends State {
def handle(context: Context): Unit = {
println("Completed: Task finished")
context.setState(new ReadyState)
}
}
class ErrorState extends State {
def handle(context: Context): Unit = {
println("Error: Something went wrong")
context.setState(new ReadyState)
}
}
class Context {
private var state: State = new ReadyState
private val data = scala.collection.mutable.Map.empty[String, Any]
def setState(state: State): Unit = {
this.state = state
}
def request(): Unit = {
state.handle(this)
}
def setData(key: String, value: Any): Unit = {
data(key) = value
}
def getData(key: String): Option[Any] = data.get(key)
}
class StatefulContext extends Context {
override def request(): Unit = {
state.handle(this)
setData("last_state", state.getClass.getSimpleName)
}
}
// Usage
val context = new Context
for (i <- 1 to 5) {
println(s"Step $i:")
context.request()
}
println("With data:")
val context2 = new StatefulContext
for (i <- 1 to 5) {
context2.setData("step", i)
context2.request()
println(s"Data: ${context2.getData("last_state")}")
}Implement proxy pattern for access control and lazy initialization.
- Proxy:
class Proxy extends Subject { private var realSubject: Option[RealSubject] = None; def request(): String = { realSubject match { case Some(subject) => subject.request(); case None => val subject = new RealSubject; realSubject = Some(subject); subject.request() } } }
// Proxy pattern
trait Subject {
def request(): String
}
class RealSubject extends Subject {
def request(): String = "RealSubject: Handling request"
}
class Proxy extends Subject {
private var realSubject: Option[RealSubject] = None
def request(): String = {
realSubject match {
case Some(subject) =>
println("Proxy: Using cached real subject")
subject.request()
case None =>
println("Proxy: Creating real subject")
val subject = new RealSubject
realSubject = Some(subject)
subject.request()
}
}
}
class LoggingProxy(subject: Subject) extends Subject {
def request(): String = {
println("Logging: Request started")
val result = subject.request()
println("Logging: Request completed")
result
}
}
class AuthProxy(subject: Subject, user: String) extends Subject {
def request(): String = {
if (authenticate()) {
println("Auth: Access granted")
subject.request()
} else {
println("Auth: Access denied")
"Unauthorized"
}
}
private def authenticate(): Boolean = user == "admin"
}
// Usage
val proxy = new Proxy
println(proxy.request())
println(proxy.request())
val real = new RealSubject
val loggingProxy = new LoggingProxy(real)
println(loggingProxy.request())
val authProxy = new AuthProxy(real, "admin")
println(authProxy.request())
val authProxy2 = new AuthProxy(real, "guest")
println(authProxy2.request())Implement flyweight pattern for sharing objects.
- Flyweight:
class Flyweight(val sharedState: String) { def operation(uniqueState: String): String = s"Shared: $sharedState, Unique: $uniqueState" } - Factory:
class FlyweightFactory { private val flyweights = mutable.Map.empty[String, Flyweight]; def getFlyweight(sharedState: String): Flyweight = { flyweights.getOrElseUpdate(sharedState, new Flyweight(sharedState)) } }
// Flyweight pattern
class Flyweight(val sharedState: String) {
def operation(uniqueState: String): String = {
s"Shared: $sharedState, Unique: $uniqueState"
}
}
class FlyweightFactory {
private val flyweights = scala.collection.mutable.Map.empty[String, Flyweight]
def getFlyweight(sharedState: String): Flyweight = {
flyweights.getOrElseUpdate(sharedState, new Flyweight(sharedState))
}
def getCount(): Int = flyweights.size
}
// Usage
val factory = new FlyweightFactory
val fw1 = factory.getFlyweight("state1")
val fw2 = factory.getFlyweight("state1")
val fw3 = factory.getFlyweight("state2")
println(s"fw1 and fw2 are same: ${fw1 == fw2}")
println(s"fw1 and fw3 are same: ${fw1 == fw3}")
println(fw1.operation("unique1"))
println(fw2.operation("unique2"))
println(fw3.operation("unique3"))
println(s"Number of flyweights: ${factory.getCount()}")Implement bridge pattern for separating abstraction from implementation.
- Abstraction:
abstract class Abstraction(protected val implementation: Implementation) { def operation(): String = implementation.operation() } - Implementation:
class ConcreteImplementationA extends Implementation { def operation(): String = "ConcreteImplementationA: Operation" }
// Bridge pattern
trait Implementation {
def operation(): String
}
class ConcreteImplementationA extends Implementation {
def operation(): String = "ConcreteImplementationA: Operation"
}
class ConcreteImplementationB extends Implementation {
def operation(): String = "ConcreteImplementationB: Operation"
}
abstract class Abstraction(protected val implementation: Implementation) {
def operation(): String = implementation.operation()
}
class ExtendedAbstraction(implementation: Implementation) extends Abstraction(implementation) {
override def operation(): String = {
s"ExtendedAbstraction: ${implementation.operation()}"
}
}
class AlternativeAbstraction(implementation: Implementation) extends Abstraction(implementation) {
override def operation(): String = {
s"AlternativeAbstraction: ${implementation.operation()}"
}
}
// Usage
val implA = new ConcreteImplementationA
val implB = new ConcreteImplementationB
val abstraction1 = new ExtendedAbstraction(implA)
val abstraction2 = new ExtendedAbstraction(implB)
val abstraction3 = new AlternativeAbstraction(implA)
println(abstraction1.operation())
println(abstraction2.operation())
println(abstraction3.operation())Implement adapter pattern for converting interfaces.
- Adapter:
class Adapter(adaptee: Adaptee) extends Target { override def request(): String = adaptee.specificRequest() }
// Adapter pattern
class Target {
def request(): String = "Target: Request"
}
class Adaptee {
def specificRequest(): String = "Adaptee: Specific Request"
}
class Adapter(adaptee: Adaptee) extends Target {
override def request(): String = adaptee.specificRequest()
}
class LoggingAdapter(adaptee: Adaptee) extends Adapter(adaptee) {
override def request(): String = {
println("Adapter: Logging request")
super.request()
}
}
// Usage
val target = new Target
val adaptee = new Adaptee
val adapter = new Adapter(adaptee)
println(target.request())
println(adapter.request())
val loggingAdapter = new LoggingAdapter(adaptee)
println(loggingAdapter.request())Implement facade pattern for simplifying complex subsystems.
- Facade:
class Facade { private val subsystemA = new SubsystemA; private val subsystemB = new SubsystemB; private val subsystemC = new SubsystemC; def simpleOperation(): String = subsystemA.operationA(); def complexOperation(): String = s"${subsystemA.operationA()} ${subsystemB.operationB()} ${subsystemC.operationC()}" }
// Facade pattern
class SubsystemA {
def operationA(): String = "SubsystemA: Operation"
}
class SubsystemB {
def operationB(): String = "SubsystemB: Operation"
}
class SubsystemC {
def operationC(): String = "SubsystemC: Operation"
}
class Facade {
private val subsystemA = new SubsystemA
private val subsystemB = new SubsystemB
private val subsystemC = new SubsystemC
def simpleOperation(): String = subsystemA.operationA()
def complexOperation(): String = {
s"${subsystemA.operationA()}
${subsystemB.operationB()}
${subsystemC.operationC()}"
}
}
// Usage
val facade = new Facade
println("Simple operation:")
println(facade.simpleOperation())
println("Complex operation:")
println(facade.complexOperation())Implement composite pattern for tree structures.
- Component:
trait Component { def operation(): String; def add(component: Component): Unit; def remove(component: Component): Unit } - Composite:
class Composite(name: String) extends Component { private val children = mutable.ListBuffer.empty[Component]; def operation(): String = { val childResults = children.map(_.operation()).mkString(" "); s"Composite $name: Operation $childResults" } }
// Composite pattern
trait Component {
def operation(): String
def add(component: Component): Unit
def remove(component: Component): Unit
def getChildren(): List[Component]
}
class Leaf(name: String) extends Component {
def operation(): String = s"Leaf $name: Operation"
def add(component: Component): Unit = throw new UnsupportedOperationException
def remove(component: Component): Unit = throw new UnsupportedOperationException
def getChildren(): List[Component] = Nil
}
class Composite(name: String) extends Component {
private val children = scala.collection.mutable.ListBuffer.empty[Component]
def operation(): String = {
val childResults = children.map(_.operation()).mkString("
")
s"Composite $name: Operation
$childResults"
}
def add(component: Component): Unit = children += component
def remove(component: Component): Unit = children -= component
def getChildren(): List[Component] = children.toList
def countLeaves(): Int = {
children.map {
case leaf: Leaf => 1
case composite: Composite => composite.countLeaves()
}.sum
}
}
// Usage
val leaf1 = new Leaf("A")
val leaf2 = new Leaf("B")
val leaf3 = new Leaf("C")
val leaf4 = new Leaf("D")
val composite1 = new Composite("Comp1")
composite1.add(leaf1)
composite1.add(leaf2)
val composite2 = new Composite("Comp2")
composite2.add(leaf3)
composite2.add(composite1)
val root = new Composite("Root")
root.add(leaf4)
root.add(composite2)
println(root.operation())
println(s"Number of leaves: ${root.countLeaves()}")Implement visitor pattern for adding operations to objects.
- Visitor:
trait Visitor { def visitA(element: ElementA): String; def visitB(element: ElementB): String } - Element:
trait Element { def accept(visitor: Visitor): String }
// Visitor pattern
trait Visitor {
def visitA(element: ElementA): String
def visitB(element: ElementB): String
}
trait Element {
def accept(visitor: Visitor): String
}
class ElementA(val data: String) extends Element {
def accept(visitor: Visitor): String = visitor.visitA(this)
}
class ElementB(val data: String) extends Element {
def accept(visitor: Visitor): String = visitor.visitB(this)
}
class ConcreteVisitor extends Visitor {
def visitA(element: ElementA): String = s"Visiting ElementA: ${element.data}"
def visitB(element: ElementB): String = s"Visiting ElementB: ${element.data}"
}
class CountingVisitor extends Visitor {
private var countA = 0
private var countB = 0
def visitA(element: ElementA): String = {
countA += 1
s"Visiting ElementA ($countA): ${element.data}"
}
def visitB(element: ElementB): String = {
countB += 1
s"Visiting ElementB ($countB): ${element.data}"
}
def getCounts(): (Int, Int) = (countA, countB)
}
class ExtendedVisitor extends Visitor {
def visitA(element: ElementA): String = s"Extended: ${element.data} (A)"
def visitB(element: ElementB): String = s"Extended: ${element.data} (B)"
}
// Usage
val elements = List(
new ElementA("Hello"),
new ElementB("World"),
new ElementA("Scala"),
new ElementB("Visitor")
)
val visitor = new ConcreteVisitor
val countingVisitor = new CountingVisitor
val extendedVisitor = new ExtendedVisitor
println("Using standard visitor:")
elements.foreach(el => println(el.accept(visitor)))
println("Using counting visitor:")
elements.foreach(el => println(el.accept(countingVisitor)))
println(s"Counts: A=${countingVisitor.getCounts()._1}, B=${countingVisitor.getCounts()._2}")
println("Using extended visitor:")
elements.foreach(el => println(el.accept(extendedVisitor)))Implement iterator pattern for sequential access.
- Iterator:
class Iterator[T](collection: List[T]) { private var position = 0; def current(): Option[T] = { if (position < collection.length) Some(collection(position)) else None }; def valid(): Boolean = position < collection.length; def next(): Unit = { position += 1 } }
// Iterator pattern
class Iterator[T](collection: List[T]) {
private var position = 0
def current(): Option[T] = {
if (position < collection.length) Some(collection(position))
else None
}
def key(): Int = position
def next(): Unit = {
position += 1
}
def rewind(): Unit = {
position = 0
}
def valid(): Boolean = position < collection.length
}
class ReverseIterator[T](collection: List[T]) {
private var position = collection.length - 1
def current(): Option[T] = {
if (position >= 0) Some(collection(position))
else None
}
def key(): Int = position
def next(): Unit = {
position -= 1
}
def rewind(): Unit = {
position = collection.length - 1
}
def valid(): Boolean = position >= 0
}
class FilteredIterator[T](collection: List[T], predicate: T => Boolean) {
private val filtered = collection.filter(predicate)
private var position = 0
def current(): Option[T] = {
if (position < filtered.length) Some(filtered(position))
else None
}
def key(): Int = position
def next(): Unit = {
position += 1
}
def rewind(): Unit = {
position = 0
}
def valid(): Boolean = position < filtered.length
}
// Usage
val collection = List("A", "B", "C", "D", "E")
val iterator = new Iterator(collection)
println("Forward iteration:")
while (iterator.valid()) {
println(iterator.current())
iterator.next()
}
val reverseIterator = new ReverseIterator(collection)
println("Reverse iteration:")
while (reverseIterator.valid()) {
println(reverseIterator.current())
reverseIterator.next()
}
val filteredIterator = new FilteredIterator(collection, (s: String) => s.length <= 1)
println("Filtered iteration:")
while (filteredIterator.valid()) {
println(filteredIterator.current())
filteredIterator.next()
}Implement template method with customizable steps.
- Template:
abstract class Template { final def templateMethod(): Unit = { println(step1()); println(step2()); println(step3()) }; protected def step1(): String; protected def step2(): String; protected def step3(): String }
// Template Method pattern
abstract class Template {
final def templateMethod(): Unit = {
println(step1())
println(step2())
println(step3())
}
protected def step1(): String
protected def step2(): String
protected def step3(): String
}
class DefaultTemplate extends Template {
protected def step1(): String = "Step 1"
protected def step2(): String = "Step 2"
protected def step3(): String = "Step 3"
}
class LoggingTemplate(template: Template) extends Template {
protected def step1(): String = {
val result = template.step1()
println(s"Logging: $result")
result
}
protected def step2(): String = {
val result = template.step2()
println(s"Logging: $result")
result
}
protected def step3(): String = {
val result = template.step3()
println(s"Logging: $result")
result
}
}
class DataProcessingTemplate(data: String) extends Template {
protected def step1(): String = s"Processing data: $data - Step 1"
protected def step2(): String = s"Processing data: $data - Step 2"
protected def step3(): String = s"Processing data: $data - Step 3"
}
// Usage
println("Using default template:")
val default = new DefaultTemplate
default.templateMethod()
println("Using logging template:")
val logging = new LoggingTemplate(default)
logging.templateMethod()
println("Using data processing template:")
val dataTemplate = new DataProcessingTemplate("example")
dataTemplate.templateMethod()Implement builder pattern for constructing complex objects.
- Builder:
class Builder { private var product = new Product; def reset(): Unit = product = new Product; def buildStepA(): Unit = product.addPart("Part A"); def getResult(): Product = { val result = product; reset(); result } }
// Builder pattern
class Product {
private val parts = scala.collection.mutable.ListBuffer.empty[String]
def addPart(part: String): Unit = parts += part
def listParts(): String = parts.mkString(", ")
}
class Builder {
private var product = new Product
def reset(): Unit = product = new Product
def buildStepA(): Unit = product.addPart("Part A")
def buildStepB(): Unit = product.addPart("Part B")
def buildStepC(): Unit = product.addPart("Part C")
def getResult(): Product = {
val result = product
reset()
result
}
}
class Director(builder: Builder) {
def buildMinimal(): Unit = {
builder.buildStepA()
}
def buildFull(): Unit = {
builder.buildStepA()
builder.buildStepB()
builder.buildStepC()
}
def buildCustom(steps: List[String]): Unit = {
builder.reset()
steps.foreach {
case "A" => builder.buildStepA()
case "B" => builder.buildStepB()
case "C" => builder.buildStepC()
}
}
}
// Usage
val builder = new Builder
val director = new Director(builder)
println("Minimal product:")
director.buildMinimal()
println(builder.getResult().listParts())
println("Full product:")
director.buildFull()
println(builder.getResult().listParts())
println("Custom product:")
builder.buildStepC()
builder.buildStepA()
println(builder.getResult().listParts())
println("Director custom:")
director.buildCustom(List("C", "A", "B"))
println(builder.getResult().listParts())Implement prototype pattern for cloning objects.
- Prototype:
class Prototype(val data: Any) { def clone(): Prototype = new Prototype(data); def deepClone(): Prototype = { data match { case map: Map[_, _] => val clonedMap = map.map { case (k, v) => (deepCloneValue(k), deepCloneValue(v)) }; new Prototype(clonedMap); case list: List[_] => new Prototype(list.map(deepCloneValue)); case _ => new Prototype(data) } } }
// Prototype pattern
class Prototype(val data: Any) {
def clone(): Prototype = new Prototype(data)
def deepClone(): Prototype = {
data match {
case map: Map[_, _] =>
val clonedMap = map.map { case (k, v) => (deepCloneValue(k), deepCloneValue(v)) }
new Prototype(clonedMap)
case list: List[_] =>
new Prototype(list.map(deepCloneValue))
case _ => new Prototype(data)
}
}
private def deepCloneValue(value: Any): Any = {
value match {
case p: Prototype => p.deepClone()
case map: Map[_, _] =>
map.map { case (k, v) => (deepCloneValue(k), deepCloneValue(v)) }
case list: List[_] =>
list.map(deepCloneValue)
case _ => value
}
}
}
class MutablePrototype(var data: Any) extends Prototype(data) {
def setData(data: Any): Unit = {
this.data = data
}
}
// Usage
val original = new Prototype(Map("name" -> "Original", "value" -> 42))
val copy = original.clone()
val deepCopy = original.deepClone()
println(s"Original: ${original.data}")
println(s"Copy: ${copy.data}")
println(s"Deep copy: ${deepCopy.data}")
val mutable = new MutablePrototype(List(1, 2, 3))
println(s"Original data: ${mutable.data}")
mutable.setData(List(4, 5, 6))
println(s"Modified data: ${mutable.data}")
val clonedMutable = mutable.clone()
println(s"Clone data: ${clonedMutable.data}")