I have the following recursive method:
def myMethod(foo: List[FooBar], acc: List[MyClass]): List[MyClass] {
// ... some code ...
myMethod(foo.tail, acc :+ getMyObject(foo.head).getOrElse(Nil))
}
The method getMyObject returns optionally an instance of MyClass. Unfortunately, I can't compile this because I get this error:
[error] found : List[Product with Serializable]
[error] required: List[MyClass]
This compile error indicates that I cannot append Nil to the list acc, so I have to use the following code:
def myMethod(foo: List[FooBar], acc: List[MyClass]): List[MyClass] {
// ... some code ...
val bar = getMyObject(foo.head)
myMethod(foo.tail, if (bar.isDefined) acc :+ bar.get else acc)
}
However, I would prefer the first approach since it is more concise. Why can't I append Nil to a list?
:+ takes an n-elemnt list and an element x and returns an n+1-element list where the last element is x. This means two things:
There's no argument that you can use as the right operand of :+ to get a list of the same size
The right operand of :+ needs to be of the element type of the list.
So you can do acc :+ Nil only if acc is a list of lists and even then it won't do what you want since it will put an additional empty list into your list, rather than keeping the list unchanged.
The most concise way to solve your problem is acc ++ bar. This uses concatenation rather than appending and works because options are seen as collections of 0 or 1 elements. So acc ++ bar appends the zero or one elements of bar to those of acc.
PS: You generally should use pattern matching or higher-order functions to operate on lists, not head and tail.
The problem is the append operation :+ takes a non-list value and appends it to the list. The trouble is Nil and Myclass are different types, so the resulting list takes the most specific type that satisfies both MyClass and Nil. They are totally unrelated types so you end up getting Product with Serializable as the common super type.
To append an element or nothing to a list, wrap that element into a list first. Then concatenate your singleton List or Nil with the old list.
myMethod(foo.tail, acc ++ getMyObject(foo.head).map(x => List(x)).getOrElse(Nil))
You are using the wrong operator, use ++ instead
myMethod(foo.tail, acc ++ getMyObject(foo.head).map(List(_)).getOrElse(Nil))
or
myMethod(foo.tail, getMyObject(foo.head).map(acc :+ _).getOrElse(acc))
Related
I'm completely new to scala and don't understand why this list isn't coming out right. When I run the program I just get List() as output when I should be getting a list of all the elements of the parameter squared. This should be very simple but the :+ operation is what I've found online and it isn't working.
def Squareall (l: List[Int]): List[Int] ={
var r : List[Int]=List()
for (i<-0 to l.length-1){
r:+ l(i)*l(i)
}
return r
}
The imperative coding style you have in your example is usually avoided in Scala. The for in Scala is an expression, meaning it results in a value, and thus you can transform your input list directly. To use a for to transform your input List you could do something like this:
def squareAll (l: List[Int]): List[Int] = {
for (i <- l) yield i * i
}
If you don't supply the yield statement a for results in the Unit type, which is like void in Java. This flavor of for loop is generally for producing side effects, like printing to the screen or writing to a file. If you really just want to transform the data, then there is no need to create and manipulate the resulting List. (Also method names in Scala are generally "camel cased".)
Most people would probably use the List.map method instead, though:
def squareAll (l: List[Int]) = l.map((x: Int) => x * x)
or even...
def squareAll (l: List[Int]) = l.map(Math.pow(_, 2.0))
You have to assign the newly created list to r like this:
r = r:+ l(i)*l(i)
This is because by default List in Scala is immutable and :+ returns a new list, doesn't update the old one.
Of course there's also a mutable variation of a list scala.collection.mutable.MutableList. You can use the .++= method on it to grow the collection.
val mutableList = scala.collection.mutable.MutableList(1, 2)
mutableList.++=(List(3, 4))
Is there any special case class for representing an empty ArrayBuffer that can be used in pattern matching similar to Nil for lists?
Also why this works:
scala> collection.mutable.ArrayBuffer.empty == Nil
res11: Boolean = true
While this does not:
scala> collection.mutable.ArrayBuffer() match { case Nil => 1 }
<console>:8: error: pattern type is incompatible with expected type;
found : scala.collection.immutable.Nil.type
required: scala.collection.mutable.ArrayBuffer[Nothing]
UPDATE
After giving it some thought I presume there is no such a case class. While existence of Nil is vital for List to work, no special structure of this kind is needed for arrays.
I've found a workaround for empty match check that might work in most cases:
collection.mutable.ArrayBuffer(2) match {
case collection.mutable.ArrayBuffer(v, _*) => v * 2
case _ => 0
}
I first check if array has at least one element and otherwise it should be empty.
Also as it turns out I could just use ArrayBuffer.isEmpty instead of pattern match.
Jasper-M provided a good answer to your second question (why == works but pattern matching fails).
As to your first, there is no equivalent to Nil for ArrayBuffer. The reason is that List is defined using scala's notion of Algebraic Data Types (ADT), while ArrayBuffer is not.
Take a look at the source for ArrayBuffer. It's implemented as a regular class, whereas List is implemented as an abstract class with two subclasses: a case object Nil, and a case class ::.
These case classes are what allow you to pattern match on List. Since there's no equivalent for ArrayBuffer, you cannot pattern match.
scala> collection.mutable.ArrayBuffer.empty == Nil
res11: Boolean = true
The reason this is true can be found by looking at the documentation of the equals method:
true if that is a sequence that has the same elements as this sequence
in the same order, false otherwise
For instance:
scala> val buffer = collection.mutable.ArrayBuffer.empty[Int]
buffer: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer()
scala> buffer.append(4)
scala> buffer == List(4)
res1: Boolean = true
So that has nothing to do with pattern matching.
After giving it some thought I presume there is no such a case class. While existence of Nil is vital for List to work, no special structure of this kind is needed for arrays.
I've found a workaround for empty match check that might work in most cases:
collection.mutable.ArrayBuffer(2) match {
case collection.mutable.ArrayBuffer(v, _*) => v * 2
case _ => 0
}
I first check if array has at least one element and otherwise it should be empty.
I am a bit new to Scala, so apologies if this is something a bit trivial.
I have a list of items which I want to iterate through. I to execute a check on each of the items and if just one of them fails I want the whole function to return false. So you can see this as an AND condition. I want it to be evaluated lazily, i.e. the moment I encounter the first false return false.
I am used to the for - yield syntax which filters items generated through some generator (list of items, sequence etc.). In my case however I just want to break out and return false without executing the rest of the loop. In normal Java one would just do a return false; within the loop.
In an inefficient way (i.e. not stopping when I encounter the first false item), I could do it:
(for {
item <- items
if !satisfiesCondition(item)
} yield item).isEmpty
Which is essentially saying that if no items make it through the filter all of them satisfy the condition. But this seems a bit convoluted and inefficient (consider you have 1 million items and the first one already did not satisfy the condition).
What is the best and most elegant way to do this in Scala?
Stopping early at the first false for a condition is done using forall in Scala. (A related question)
Your solution rewritten:
items.forall(satisfiesCondition)
To demonstrate short-circuiting:
List(1,2,3,4,5,6).forall { x => println(x); x < 3 }
1
2
3
res1: Boolean = false
The opposite of forall is exists which stops as soon as a condition is met:
List(1,2,3,4,5,6).exists{ x => println(x); x > 3 }
1
2
3
4
res2: Boolean = true
Scala's for comprehensions are not general iterations. That means they cannot produce every possible result that one can produce out of an iteration, as, for example, the very thing you want to do.
There are three things that a Scala for comprehension can do, when you are returning a value (that is, using yield). In the most basic case, it can do this:
Given an object of type M[A], and a function A => B (that is, which returns an object of type B when given an object of type A), return an object of type M[B];
For example, given a sequence of characters, Seq[Char], get UTF-16 integer for that character:
val codes = for (char <- "A String") yield char.toInt
The expression char.toInt converts a Char into an Int, so the String -- which is implicitly converted into a Seq[Char] in Scala --, becomes a Seq[Int] (actually, an IndexedSeq[Int], through some Scala collection magic).
The second thing it can do is this:
Given objects of type M[A], M[B], M[C], etc, and a function of A, B, C, etc into D, return an object of type M[D];
You can think of this as a generalization of the previous transformation, though not everything that could support the previous transformation can necessarily support this transformation. For example, we could produce coordinates for all coordinates of a battleship game like this:
val coords = for {
column <- 'A' to 'L'
row <- 1 to 10
} yield s"$column$row"
In this case, we have objects of the types Seq[Char] and Seq[Int], and a function (Char, Int) => String, so we get back a Seq[String].
The third, and final, thing a for comprehension can do is this:
Given an object of type M[A], such that the type M[T] has a zero value for any type T, a function A => B, and a condition A => Boolean, return either the zero or an object of type M[B], depending on the condition;
This one is harder to understand, though it may look simple at first. Let's look at something that looks simple first, say, finding all vowels in a sequence of characters:
def vowels(s: String) = for {
letter <- s
if Set('a', 'e', 'i', 'o', 'u') contains letter.toLower
} yield letter.toLower
val aStringVowels = vowels("A String")
It looks simple: we have a condition, we have a function Char => Char, and we get a result, and there doesn't seem to be any need for a "zero" of any kind. In this case, the zero would be the empty sequence, but it hardly seems worth mentioning it.
To explain it better, I'll switch from Seq to Option. An Option[A] has two sub-types: Some[A] and None. The zero, evidently, is the None. It is used when you need to represent the possible absence of a value, or the value itself.
Now, let's say we have a web server where users who are logged in and are administrators get extra javascript on their web pages for administration tasks (like wordpress does). First, we need to get the user, if there's a user logged in, let's say this is done by this method:
def getUser(req: HttpRequest): Option[User]
If the user is not logged in, we get None, otherwise we get Some(user), where user is the data structure with information about the user that made the request. We can then model that operation like this:
def adminJs(req; HttpRequest): Option[String] = for {
user <- getUser(req)
if user.isAdmin
} yield adminScriptForUser(user)
Here it is easier to see the point of the zero. When the condition is false, adminScriptForUser(user) cannot be executed, so the for comprehension needs something to return instead, and that something is the "zero": None.
In technical terms, Scala's for comprehensions provides syntactic sugars for operations on monads, with an extra operation for monads with zero (see list comprehensions in the same article).
What you actually want to accomplish is called a catamorphism, usually represented as a fold method, which can be thought of as a function of M[A] => B. You can write it with fold, foldLeft or foldRight in a sequence, but none of them would actually short-circuit the iteration.
Short-circuiting arises naturally out of non-strict evaluation, which is the default in Haskell, in which most of these papers are written. Scala, as most other languages, is by default strict.
There are three solutions to your problem:
Use the special methods forall or exists, which target your precise use case, though they don't solve the generic problem;
Use a non-strict collection; there's Scala's Stream, but it has problems that prevents its effective use. The Scalaz library can help you there;
Use an early return, which is how Scala library solves this problem in the general case (in specific cases, it uses better optimizations).
As an example of the third option, you could write this:
def hasEven(xs: List[Int]): Boolean = {
for (x <- xs) if (x % 2 == 0) return true
false
}
Note as well that this is called a "for loop", not a "for comprehension", because it doesn't return a value (well, it returns Unit), since it doesn't have the yield keyword.
You can read more about real generic iteration in the article The Essence of The Iterator Pattern, which is a Scala experiment with the concepts described in the paper by the same name.
forall is definitely the best choice for the specific scenario but for illustration here's good old recursion:
#tailrec def hasEven(xs: List[Int]): Boolean = xs match {
case head :: tail if head % 2 == 0 => true
case Nil => false
case _ => hasEven(xs.tail)
}
I tend to use recursion a lot for loops w/short circuit use cases that don't involve collections.
UPDATE:
DO NOT USE THE CODE IN MY ANSWER BELOW!
Shortly after I posted the answer below (after misinterpreting the original poster's question), I have discovered a way superior generic answer (to the listing of requirements below) here: https://stackoverflow.com/a/60177908/501113
It appears you have several requirements:
Iterate through a (possibly large) list of items doing some (possibly expensive) work
The work done to an item could return an error
At the first item that returns an error, short circuit the iteration, throw away the work already done, and return the item's error
A for comprehension isn't designed for this (as is detailed in the other answers).
And I was unable to find another Scala collections pre-built iterator that provided the requirements above.
While the code below is based on a contrived example (transforming a String of digits into a BigInt), it is the general pattern I prefer to use; i.e. process a collection and transform it into something else.
def getDigits(shouldOnlyBeDigits: String): Either[IllegalArgumentException, BigInt] = {
#scala.annotation.tailrec
def recursive(
charactersRemaining: String = shouldOnlyBeDigits
, accumulator: List[Int] = Nil
): Either[IllegalArgumentException, List[Int]] =
if (charactersRemaining.isEmpty)
Right(accumulator) //All work completed without error
else {
val item = charactersRemaining.head
val isSuccess =
item.isDigit //Work the item
if (isSuccess)
//This item's work completed without error, so keep iterating
recursive(charactersRemaining.tail, (item - 48) :: accumulator)
else {
//This item hit an error, so short circuit
Left(new IllegalArgumentException(s"item [$item] is not a digit"))
}
}
recursive().map(digits => BigInt(digits.reverse.mkString))
}
When it is called as getDigits("1234") in a REPL (or Scala Worksheet), it returns:
val res0: Either[IllegalArgumentException,BigInt] = Right(1234)
And when called as getDigits("12A34") in a REPL (or Scala Worksheet), it returns:
val res1: Either[IllegalArgumentException,BigInt] = Left(java.lang.IllegalArgumentException: item [A] is not digit)
You can play with this in Scastie here:
https://scastie.scala-lang.org/7ddVynRITIOqUflQybfXUA
I create a List like this :
var multiList : List[MyObj] = Nil
To append objects to this List I use :
multiList = multiList ::: List(MyObj)
this works but should I not be using
multiList = multiList ::: MyObj
as here I am appending an object to the List, wheras in example (that works) it looks syntactically as if im appending a new List to a List ?
The ::: operators mean concatenate, not append. There's :+ for element-append.
The :: method is used to 'prepend' stuff to a list. The ::: operator is used to prepend one list to another. The :: ends with a colon and thus is 'right associative' which can be explained as follows
x :: y
// will be translated to
y.::(x)
So to add your object to an empty list you could do
MyObj :: Nil
// will be translated to
Nil.::(MyObj)
If you wanted to add a list of objects to an empty list you could do
List(MyObj, MyObj) ::: Nil
// will be translated to
Nil.:::(List(MyObj, MyObj))
If you do want to append you could use the :+ method. This however performs differently for different types of collections. More info about the perfomance can be found here: Performance Characteristics
Below is an implementation of a function that returns the lexographically next permutation. This is useful in one of the Euler problems.
It's written to work on Strings (which I needed for that). However, it should work on any indexed sequence of comparable values. I've tried generalising it by changing the two occurrences of String to IndexedSeq[Char], but this gets an error:
euler-lib.scala:26: error: type mismatch;
found : IndexedSeq[Char]
required: String
((n.slice(pivot+1, successor):+ n(pivot)) + n.drop(successor+1)).reverse
^
Why has the type inferencer inferred String there? I don't seem to have done any operation that requires a String?
And can I make it more general still by having IndexedSeq["something-comparable"]? I've not been able to make this work.
// return the lexographically next permutation to the one passed as a parameter
// pseudo-code from an article on StackOverflow
def nextPermutation(n:String):String = {
// 1. scan the array from right-to-left
//1.1. if the current element is less than its right-hand neighbor,
// call the current element the pivot,
// and stop scanning
// (We scan left-to-right and return the last such).
val pivot = n.zip(n.tail).lastIndexWhere{ case (first, second) => first < second }
//1.2. if the left end is reached without finding a pivot,
// reverse the array and return
// (the permutation was the lexicographically last, so its time to start over)
if (pivot < 0) return n.reverse
//2. scan the array from right-to-left again,
// to find the rightmost element larger than the pivot
// (call that one the successor)
val successor = n.lastIndexWhere{_ > n(pivot)}
//3. swap the pivot and the successor, and
//4. reverse the portion of the array to the right of where the pivot was found
return (n.take(pivot) :+ n(successor)) +
((n.slice(pivot+1, successor):+ n(pivot)) + n.drop(successor+1)).reverse
}
The method + in IndexedSeq is used to produce a new sequence containing one additional given element but you want to produce one containing an additional sequence. The method for this is ++ thus your last line must look like this:
(n.take(pivot) :+ n(successor)) ++
((n.slice(pivot+1, successor):+ n(pivot)) ++ n.drop(successor+1)).reverse
You are seeing this strange compiler message about a String being expected because +'s signature does not match and thus an explicit conversion used for String concatenation kicks in (this conversion is there because it lets you write something like List(8) + " Test").
EDIT: Generalization over sequence types of ordered elements:
As I said in the comments, generalization over sequences is a bit more complicated. In addition to your element type A you will need another type CC[X] <: SeqLike[X,CC[X]] that represents the sequence. Normally C <: SeqLike[A,C] would be sufficient but the type inferencer does not like that one (you would always need to pass the types of A and C when calling that method).
If you just change your signature that way the compiler will complain that it requires an implicit CanBuildFrom[CC[A],A,CC[A]] parameter as that one is needed e.g. by the reverse method. That parameter is used to build one sequence type from another one - just search the site to see some examples of how it is used by the collections API.
The final result would look like this:
import collection.SeqLike
import collection.generic.CanBuildFrom
def nextPermutation[A, CC[X] <: SeqLike[X,CC[X]]](n: CC[A])(
implicit ord: Ordering[A], bf: CanBuildFrom[CC[A],A,CC[A]]): CC[A] = {
import ord._
// call toSeq to avoid having to require an implicit CanBuildFrom for (A,A)
val pivot = n.toSeq.zip(n.tail.toSeq).lastIndexWhere{
case (first, second) => first < second
}
if (pivot < 0) {
n.reverse
}
else {
val successor = n.lastIndexWhere{_ > n(pivot)}
(n.take(pivot) :+ n(successor)) ++
((n.slice(pivot+1, successor):+ n(pivot)) ++ n.drop(successor+1)).reverse
}
}
This way you get a Vector[Int] if you passed one to the method and a List[Double] if you passed that to the method. So what about Strings? Those are not actual sequences but they can be implicitly converted into a Seq[Char]. It is possible alter the definition of that method expect some type that can be implicitly converted into a Seq[A] but then again type inference would not work reliably - or at least I could not make it work reliably. As a simple workaround you could define an additional method for Strings:
def nextPermutation(s: String): String =
nextPermutation[Char,Seq](s.toSeq).mkString
Little tip here:
n(pivot)) + n.drop(successor+1)
^
When you get a type mismatch error, and the ^ points to the first parenthesis of the last argument list (ie, it would point to the second ( in x.foldLeft(y)(z)), that means the value returned by that method has the wrong type.
Or, in this case, n.drop(sucessor+1) has type IndexedSeq[Char], but the + method expects a String.
Another little tip: the only things that accept + are the numeric classes and String. If you try to add things and get an error, most likely it is Scala thinking you are using + to add Strings. For example:
true + true // expected String, got Boolean error
"true" + true // works, the second true is converted to String
true + "true" // works, the first true is converted to String
So, avoid + unless you are working with numbers or strings.
So, about making that general...
def nextPermutation[A <% Ordered[A]](n: IndexedSeq[A]): IndexedSeq[A] = {
val pivot = n.zip(n.tail).lastIndexWhere{ case (first, second) => first < second }
if (pivot < 0) return n.reverse
val successor = n.lastIndexWhere{_ > n(pivot)}
return (n.take(pivot) :+ n(successor)) ++
((n.slice(pivot+1, successor):+ n(pivot)) ++ n.drop(successor+1)).reverse
}
The easy part is just declaring IndexedSeq. But you have to parameterize on A, and there must be a way to order A so that you can compare the elements (<% means there's an implicit conversion from A to an Ordered[A] available). Another way to declare it would be like this:
def nextPermutation[A : Ordering](n: IndexedSeq[A]): IndexedSeq[A] = {
val ordering = implicitly[Ordering[A]]; import ordering._
val pivot = n.zip(n.tail).lastIndexWhere{ case (first, second) => first < second }
if (pivot < 0) return n.reverse
val successor = n.lastIndexWhere{_ > n(pivot)}
return (n.take(pivot) :+ n(successor)) ++
((n.slice(pivot+1, successor):+ n(pivot)) ++ n.drop(successor+1)).reverse
}
Here, A : Ordering means there is an implicit Ordering[A] available, which is then obtained and imported into scope, so that it can offer implicit conversions to make < work. The difference between an Ordered[A] and an Ordering[A] can be found on other questions.
Problem 24 had me stumped for a while:
println("0123456789".permutations.drop(1000000 - 1).next);
The code compiles correclty for me in Scala 2.8.0. Which version of Scala are you using ?
scala> nextPermutation("12354")
res0: String = 12435