You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
valn=10vallist1= ((1 until n) map ( i => (1 until i) map (j => (i, j)))).flatten
vallist2= (1 until n) flatMap (i => (1 until i) map (j => (i, j)))
//list2: scala.collection.immutable.IndexedSeq[(Int, Int)] = Vector((2,1), (3,1), (3,2), (4,1), (4,2), (4,3), (5,1), (5,2), (5,3), (5,4), (6,1), (6,2), (6,3), (6,4), (6,5), (7,1), (7,2), (7,3), (7,4), (7,5), (7,6), (8,1), (8,2), (8,3), (8,4), (8,5), (8,6), (8,7), (9,1), (9,2), (9,3), (9,4), (9,5), (9,6), (9,7), (9,8))vallist3=for {
i <-1 until n
j <-1 until i
} yield (i, j)
For expression
valpixels= {
for (
i <--radius to radius;
j <--radius to radius
) yield (scalashop.clamp(x + i, 0, src.width -1), scalashop.clamp(y + j, 0, src.height -1))
}.distinct.map({
case (x, y) =>valpixel= src(x, y)
(red(pixel), green(pixel), blue(pixel), alpha(pixel))
})
While loops
varr, g, b, a=0vartotal=0varxi= clamp(x-radius, 0, src.width-1)
while(xi<=clamp(x+radius, 0, src.width-1)) {
varyi= clamp(y-radius, 0, src.height-1)
while(yi<=clamp(y+radius, 0, src.height-1)) {
r = r + red(src(xi, yi))
g = g + green(src(xi, yi))
b = b + blue(src(xi, yi))
a = a + alpha(src(xi, yi))
total = total +1
yi = yi +1
}
xi = xi +1
}
The fold method takes an associative binary operator function as parameter and will use it to collapse elements from the collection. The fold method allows you to also specify an initial value.
simple Fold
The fold method for a List takes two arguments; the start value and a function.
This function also takes two arguments; the accumulated value and the current item in the list.
valnumbers=List(5, 4, 8, 6, 2)
numbers.fold(0) { (acc, i) =>
acc + i
}
// result = 25
LeftFold
foldLeft starts on the left side—the first item—and iterates to the right;
foldLeft associates to the left. I.e. an accumulator will be initialized and elements will be added to the accumulator in left-to-right order
Applies a binary operator to a start value and all elements of this list, going left to right.
valstringList= fooList.foldLeft(List[String]()) { (z, f) =>valtitle= f.sex match {
case'male=>"Mr."case'female=>"Ms."
}
z :+s"$title${f.name}, ${f.age}"
}
// stringList(0)// Mr. Hugh Jass, 25// stringList(2)// Ms. Incontinentia Buttocks, 37
RightFold
foldRight starts on the right side—the last item—and iterates to the left.
foldRight associates to the right. I.e. elements will be accumulated in right-to-left order:
The primary difference is the order in which the fold operation iterates through the collection in question.
foldLeft starts on the left side—the first item—and iterates to the right;
foldRight starts on the right side—the last item—and iterates to the left.
fold goes in no particular order.
Because fold does not go in any particular order, there are constraints on the start value and thus return value (in all three folds the type of the start value must be the same as the return value).
The first constraint is that the start value must be a supertype of the object you're folding. In our first example we were folding on a type List[Int] and had a start type of Int. Int is a supertype of List[Int].
The second constraint of fold is that the start value must be neutral, i.e. it must not change the result. For example, the neutral value for an addition operation would be 0, 1 for multiplication, Nil lists, etc.
This cheat sheet originated from the forum, credits to Laurent Poulain.
We copied it and changed or added a few things.
There are certainly a lot of things that can be improved! If you would like to contribute, you have two options:
Call by value: evaluates the function arguments before calling the function
Call by name: evaluates the function first, and then evaluates the arguments if need be
defexample=2// evaluated when calledvalexample=2// evaluated immediatelylazyvalexample=2// evaluated once when neededdefsquare(x: Double) // call by valuedefsquare(x: =>Double) // call by namedefmyFct(bindings: Int*) = { ... } // bindings is a sequence of int, containing a varying # of arguments
Higher order functions
These are functions that take a function as a parameter or return functions.
// sum() returns a function that takes two integers and returns an integer defsum(f: Int=>Int): (Int, Int) =>Int= {
defsumf(a: Int, b: Int):Int= {...}
sumf
}
// same as above. Its type is (Int => Int) => (Int, Int) => Int defsum(f: Int=>Int)(a: Int, b: Int):Int= { ... }
// Called like this
sum((x: Int) => x * x * x) // Anonymous function, i.e. does not have a name
sum(x => x * x * x) // Same anonymous function with type inferreddefcube(x: Int) = x * x * x
sum(x => x * x * x)(1, 10) // sum of cubes from 1 to 10
sum(cube)(1, 10) // same as above
Currying
Converting a function with multiple arguments into a function with a
single argument that returns another function.
deff(a: Int, b: Int):Int// uncurried version (type is (Int, Int) => Int)deff(a: Int)(b: Int):Int// curried version (type is Int => Int => Int)
Classes
classMyClass(x: Int, y: Int) { // Defines a new type MyClass with a constructor
require(y >0, "y must be positive") // precondition, triggering an IllegalArgumentException if not met defthis (x: Int) = { ... } // auxiliary constructor defnb1= x // public method computed every time it is called defnb2= y
privatedeftest(a: Int):Int= { ... } // private method valnb3= x + y // computed only once overridedeftoString=// overridden method
member1 +", "+ member2
}
newMyClass(1, 2) // creates a new object of type
this references the current object, assert(<condition>) issues AssertionError if condition
is not met. See scala.Predef for require, assume and assert.
Operators
myObject myMethod 1 is the same as calling myObject.myMethod(1)
Operator (i.e. function) names can be alphanumeric, symbolic (e.g. x1, *, +?%&, vector_++, counter_=)
The precedence of an operator is determined by its first character, with the following increasing order of priority:
(all letters)
|
^
&
< >
= !
:
+ -
* / %
(all other special characters)
The associativity of an operator is determined by its last character: Right-associative if ending with :, Left-associative otherwise.
Note that assignment operators have lowest precedence. (Read Scala Language Specification 2.9 sections 6.12.3, 6.12.4 for more info)
Class hierarchies
abstractclassTopLevel { // abstract class defmethod1(x: Int):Int// abstract method defmethod2(x: Int):Int= { ... }
}
classLevel1extendsTopLevel {
defmethod1(x: Int):Int= { ... }
overridedefmethod2(x: Int):Int= { ...} // TopLevel's method2 needs to be explicitly overridden
}
objectMyObjectextendsTopLevel { ... } // defines a singleton object. No other instance can be created
Classes and objects are organized in packages (package myPackage).
They can be referenced through import statements (import myPackage.MyClass, import myPackage._,
import myPackage.{MyClass1, MyClass2}, import myPackage.{MyClass1 => A})
They can also be directly referenced in the code with the fully qualified name (new myPackage.MyClass1)
All members of packages scala and java.lang as well as all members of the object scala.Predef are automatically imported.
Traits are similar to Java interfaces, except they can have non-abstract members:
scala.Any base type of all types. Has methods hashCode and toString that can be overridden
scala.AnyVal base type of all primitive types. (scala.Double, scala.Float, etc.)
scala.AnyRef base type of all reference types. (alias of java.lang.Object, supertype of java.lang.String, scala.List, any user-defined class)
scala.Null is a subtype of any scala.AnyRef (null is the only instance of type Null), and scala.Nothing is a subtype of any other type without any instance.
Type Parameters
Conceptually similar to C++ templates or Java generics. These can apply to classes, traits or functions.
classMyClass[T](arg1: T) { ... }
newMyClass[Int](1)
newMyClass(1) // the type is being inferred, i.e. determined based on the value arguments
It is possible to restrict the type being used, e.g.
defmyFct[T<:TopLevel](arg: T):T= { ... } // T must derive from TopLevel or be TopLeveldefmyFct[T>:Level1](arg: T):T= { ... } // T must be a supertype of Level1defmyFct[T>:Level1<:TopLevel](arg: T):T= { ... }
Variance
Given A <: B
If C[A] <: C[B], C is covariant
If C[A] >: C[B], C is contravariant
Otherwise C is nonvariant
classC[+A] { ... } // C is covariantclassC[-A] { ... } // C is contravariantclassC[A] { ... } // C is nonvariant
For a function, if A2 <: A1 and B1 <: B2, then A1 => B1 <: A2 => B2.
Functions must be contravariant in their argument types and covariant in their result types, e.g.
traitFunction1[-T, +U] {
defapply(x: T):U
} // Variance check is OK because T is contravariant and U is covariantclassArray[+T] {
defupdate(x: T)
} // variance checks fails
Pattern matching is used for decomposing data structures:
unknownObject match {
caseMyClass(n) => ...
caseMyClass2(a, b) => ...
}
Here are a few example patterns
(someList: List[T]) match {
caseNil=> ... // empty listcase x ::Nil=> ... // list with only one elementcaseList(x) => ... // same as abovecase x :: xs => ... // a list with at least one element. x is bound to the head,// xs to the tail. xs could be Nil or some other list.case1::2:: cs => ... // lists that starts with 1 and then 2case (x, y) :: ps => ... // a list where the head element is a paircase _ => ... // default case if none of the above matches
}
The last example shows that every pattern consists of sub-patterns: it
only matches lists with at least one element, where that element is a
pair. x and y are again patterns that could match only specific
types.
Options
Pattern matching can also be used for Option values. Some
functions (like Map.get) return a value of type Option[T] which
is either a value of type Some[T] or the value None:
valmyMap=Map("a"->42, "b"->43)
defgetMapValue(s: String):String= {
myMap get s match {
caseSome(nb) =>"Value found: "+ nb
caseNone=>"No value found"
}
}
getMapValue("a") // "Value found: 42"
getMapValue("c") // "No value found"
Most of the times when you write a pattern match on an option value,
the same expression can be written more concisely using combinator
methods of the Option class. For example, the function getMapValue
can be written as follows:
defgetMapValue(s: String):String=
myMap.get(s).map("Value found: "+ _).getOrElse("No value found")
Pattern Matching in Anonymous Functions
Pattern matches are also used quite often in anonymous functions:
valpairs:List[(Char, Int)] = ('a', 2) :: ('b', 3) ::Nilvalchars:List[Char] = pairs.map(p => p match {
case (ch, num) => ch
})
Instead of p => p match { case ... }, you can simply write {case ...}, so the above example becomes more concise:
Array (Scala arrays are native JVM arrays at runtime, therefore they are very performant)
Scala also has mutable maps and sets; these should only be used if there are performance issues with immutable types
Examples
valfruitList=List("apples", "oranges", "pears")
// Alternative syntax for listsvalfruit="apples":: ("oranges":: ("pears"::Nil)) // parens optional, :: is right-associative
fruit.head // "apples"
fruit.tail // List("oranges", "pears")valempty=List()
valempty=Nilvalnums=Vector("louis", "frank", "hiromi")
nums(1) // element at index 1, returns "frank", complexity O(log(n))
nums.updated(2, "helena") // new vector with a different string at index 2, complexity O(log(n))valfruitSet=Set("apple", "banana", "pear", "banana")
fruitSet.size // returns 3: there are no duplicates, only one bananavalr:Range=1 until 5// 1, 2, 3, 4vals:Range=1 to 5// 1, 2, 3, 4, 51 to 10 by 3// 1, 4, 7, 106 to 1 by -2// 6, 4, 2vals= (1 to 6).toSet
s map (_ +2) // adds 2 to each element of the setvals="Hello World"
s filter (c => c.isUpper) // returns "HW"; strings can be treated as Seq[Char]// Operations on sequencesvalxs=List(...)
xs.length // number of elements, complexity O(n)
xs.last // last element (exception if xs is empty), complexity O(n)
xs.init // all elements of xs but the last (exception if xs is empty), complexity O(n)
xs take n // first n elements of xs
xs drop n // the rest of the collection after taking n elements
xs(n) // the nth element of xs, complexity O(n)
xs ++ ys // concatenation, complexity O(n)
xs.reverse // reverse the order, complexity O(n)
xs updated(n, x) // same list than xs, except at index n where it contains x, complexity O(n)
xs indexOf x // the index of the first element equal to x (-1 otherwise)
xs contains x // same as xs indexOf x >= 0
xs filter p // returns a list of the elements that satisfy the predicate p
xs filterNot p // filter with negated p
xs partition p // same as (xs filter p, xs filterNot p)
xs takeWhile p // the longest prefix consisting of elements that satisfy p
xs dropWhile p // the remainder of the list after any leading element satisfying p have been removed
xs span p // same as (xs takeWhile p, xs dropWhile p)List(x1, ..., xn) reduceLeft op // (...(x1 op x2) op x3) op ...) op xnList(x1, ..., xn).foldLeft(z)(op) // (...( z op x1) op x2) op ...) op xnList(x1, ..., xn) reduceRight op // x1 op (... (x{n-1} op xn) ...)List(x1, ..., xn).foldRight(z)(op) // x1 op (... ( xn op z) ...)
xs exists p // true if there is at least one element for which predicate p is true
xs forall p // true if p(x) is true for all elements
xs zip ys // returns a list of pairs which groups elements with same index together
xs unzip // opposite of zip: returns a pair of two lists
xs.flatMap f // applies the function to all elements and concatenates the result
xs.sum // sum of elements of the numeric collection
xs.product // product of elements of the numeric collection
xs.max // maximum of collection
xs.min // minimum of collection
xs.flatten // flattens a collection of collection into a single-level collection
xs groupBy f // returns a map which points to a list of elements
xs distinct // sequence of distinct entries (removes duplicates)
x +: xs // creates a new collection with leading element x
xs :+ x // creates a new collection with trailing element x// Operations on mapsvalmyMap=Map("I"->1, "V"->5, "X"->10) // create a map
myMap("I") // => 1
myMap("A") // => java.util.NoSuchElementException
myMap get "A"// => None
myMap get "I"// => Some(1)
myMap.updated("V", 15) // returns a new map where "V" maps to 15 (entry is updated)// if the key ("V" here) does not exist, a new entry is added// Operations on Streamsvalxs=Stream(1, 2, 3)
valxs=Stream.cons(1, Stream.cons(2, Stream.cons(3, Stream.empty))) // same as above
(1 to 1000).toStream // => Stream(1, ?)
x #:: xs // Same as Stream.cons(x, xs)// In the Stream's cons operator, the second parameter (the tail)// is defined as a "call by name" parameter.// Note that x::xs always produces a List
There is already a class in the standard library that represents orderings: scala.math.Ordering[T] which contains
comparison functions such as lt() and gt() for standard types. Types with a single natural ordering should inherit from
the trait scala.math.Ordered[T].
importmath.Orderingdefmsort[T](xs: List[T])(implicitord: Ordering) = { ...}
msort(fruits)(Ordering.String)
msort(fruits) // the compiler figures out the right ordering
For-Comprehensions
A for-comprehension is syntactic sugar for map, flatMap and filter operations on collections.
The general form is for (s) yield e
s is a sequence of generators and filters
p <- e is a generator
if f is a filter
If there are several generators (equivalent of a nested loop), the last generator varies faster than the first
You can use { s } instead of ( s ) if you want to use multiple lines without requiring semicolons
e is an element of the resulting collection
Example 1
// list all combinations of numbers x and y where x is drawn from// 1 to M and y is drawn from 1 to Nfor (x <-1 to M; y <-1 to N)
yield (x,y)
is equivalent to
(1 to M) flatMap (x => (1 to N) map (y => (x, y)))
Translation Rules
A for-expression looks like a traditional for loop but works differently internally
for (x <- e1) yield e2 is translated to e1.map(x => e2)
for (x <- e1 if f) yield e2 is translated to for (x <- e1.filter(x => f)) yield e2
for (x <- e1; y <- e2) yield e3 is translated to e1.flatMap(x => for (y <- e2) yield e3)
This means you can use a for-comprehension for your own type, as long
as you define map, flatMap and filter.
place N queens on a NxN chess board without the queens attacking each other
objectnqueens {
/** * place N queens on a NxN chess board without the queens attacking each other * */defqueens(n: Int):Set[List[Int]] = {
defplaceQueens(k: Int):Set[List[Int]] =if (k ==0) Set(List())
elsefor {
queens <- placeQueens(k -1)
col <-0 until n
if isSafe(col, queens)
} yield col :: queens
placeQueens(n)
}
defisSafe(col: Int, queens: List[Int]):Boolean= {
valrow= queens.length
valqueensWithRow= (row -1 to 0 by -1) zip queens
queensWithRow forall {
case (r, c) => col != c && math.abs(col - c) != row - r
}
}
defshow(queens: List[Int]) = {
vallines=for( col <- queens.reverse)
yieldVector.fill(queens.length)("*").updated(col, "X").mkString
"\n"+ (lines mkString "\n")
}
(queens(8) take 3 map show) mkString "\n"
}