I have a for comprehension like:
val ao = Option(1)
val bo = Option(2)
val (x,y) = for (a <- ao; b <- bo) yield (a+b, b+a*2)
However this does not work. For comprehension returns Option[(Int,Int)] but cannot be assigned to individual x and y.
If I do:
val Some((x,y)) = for ...
It causes exception when yield None.
How to achieve this goal? I want x and y to be Option[Int]. I hope to find an elegant solution without using like x._1 or x.getOrElse, or match
It should have been unzip, but unfortunately, unzip returns Lists, not Options. Probably the shortest work-around would be:
val pairOpt = for (a <- ao; b <- bo) yield (a+b, b+a*2)
val (x, y) = (pairOpt.map(_._1), pairOpt.map(_._2))
Isn't pattern matching the best way to handle options?
val res = for (a <- ao; b <- bo) yield (a+b, b+a*2)
val (x, y) = res match {
case Some((x, y)) => (Some(x), Some(y))
case None => (None, None)
}
Why would that not be considered 'elegant'?
Related
I am wondering how you can append, say, variable x of type A to Option[List[A]].
val opt = Option[List[A]] which is initially None.
Now how can I add x to the List of A?
Is it:
opt.get ++ x
Does it change the opt value by using get?
Hope my question is clear
Does it change the opt value by using get?
No, List[A] is immutable, in the case of using opt.get ++ List(x) you'd get back a new list. I wouldn't recommend using .get directly.
Instead, you can use map and orElse in case the list is None to begin with:
val result: Option[List[A]] = opt.map(list => x +: list).orElse(Option(List(x)))
An additional approach can be using Option[A].fold:
val result: Seq[Int] = opt.fold(List(x))(list => x +: list)
If you want to prepend the element and extract the list, use getOrElse:
val result: Seq[Int] = opt.map(list => x +: list).getOrElse(List(10))
I actually solved this by doing
val result = Option(opt.get ++ x )
I am representing a graph's adjacency list in Scala in the variable a.
val a = new HashMap[Int, Vector[Tuple2[Int, Int]]] withDefaultValue Vector.empty
for(i <- 1 to N) {
val Array(x, y, r) = readLine.split(" ").map(_.toInt)
a(x) += new Tuple2(y, r)
a(y) += new Tuple2(x, r)
}
I am reading each edge in turn(x and y are nodes, while r is the cost of the edge). After reading it, I am adding it to the adjacency list.
However, when adding the Tuples containing a neighbouring node and a cost to the HashMap I get:
Solution.scala:17: error: type mismatch;
found : (Int, Int)
required: String
a(x) += new Tuple2(y, r)
I don't understand why it wants String. I haven't specified String anywhere.
+= is the operator for concatenating to a String.
You would probably want to do something like: a.update(x, a.getOrElse(x, Vector()) :+ (x, r)).
Also, you are writing Java code in Scala. It compiles, but amounts to abuse of the language :/
Consider doing something like this next time:
val a = Range(1, N)
.map { _ => readline.split(" ").map (_.toInt) }
.flatMap { case Array(x, y, r) =>
Seq(x -> (y, r), y -> (x, r))
}
.groupBy(_._1)
.mapValues { _.map ( _._2) }
I am trying to map a subset of a sequence using another (shorter) sequence while preserving the elements that are not in the subset. A toy example below tries to give a flower to females only:
def giveFemalesFlowers(people: Seq[Person], flowers: Seq[Flower]): Seq[Person] = {
require(people.count(_.isFemale) == flowers.length)
magic(people, flowers)(_.isFemale)((p, f) => p.withFlower(f))
}
def magic(people: Seq[Person], flowers: Seq[Flower])(predicate: Person => Boolean)
(mapping: (Person, Flower) => Person): Seq[Person] = ???
Is there an elegant way to implement the magic?
Use an iterator over flowers, consume one each time the predicate holds; the code would look like this,
val it = flowers.iterator
people.map ( p => if (predicate(p)) p.withFlowers(it.next) else p )
What about zip (aka zipWith) ?
scala> val people = List("m","m","m","f","f","m","f")
people: List[String] = List(m, m, m, f, f, m, f)
scala> val flowers = List("f1","f2","f3")
flowers: List[String] = List(f1, f2, f3)
scala> def comb(xs:List[String],ys:List[String]):List[String] = (xs,ys) match {
| case (x :: xs, y :: ys) if x=="f" => (x+y) :: comb(xs,ys)
| case (x :: xs,ys) => x :: comb(xs,ys)
| case (Nil,Nil) => Nil
| }
scala> comb(people, flowers)
res1: List[String] = List(m, m, m, ff1, ff2, m, ff3)
If the order is not important, you can get this elegant code:
scala> val (men,women) = people.partition(_=="m")
men: List[String] = List(m, m, m, m)
women: List[String] = List(f, f, f)
scala> men ++ (women,flowers).zipped.map(_+_)
res2: List[String] = List(m, m, m, m, ff1, ff2, ff3)
I am going to presume you want to retain all the starting people (not simply filter out the females and lose the males), and in the original order, too.
Hmm, bit ugly, but what I came up with was:
def giveFemalesFlowers(people: Seq[Person], flowers: Seq[Flower]): Seq[Person] = {
require(people.count(_.isFemale) == flowers.length)
people.foldLeft((List[Person]() -> flowers)){ (acc, p) => p match {
case pp: Person if pp.isFemale => ( (pp.withFlower(acc._2.head) :: acc._1) -> acc._2.tail)
case pp: Person => ( (pp :: acc._1) -> acc._2)
} }._1.reverse
}
Basically, a fold-left, initialising the 'accumulator' with a pair made up of an empty list of people and the full list of flowers, then cycling through the people passed in.
If the current person is female, pass it the head of the current list of flowers (field 2 of the 'accumulator'), then set the updated accumulator to be the updated person prepended to the (growing) list of processed people, and the tail of the (shrinking) list of flowers.
If male, just prepend to the list of processed people, leaving the flowers unchanged.
By the end of the fold, field 2 of the 'accumulator' (the flowers) should be an empty list, while field one holds all the people (with any females having each received their own flower), in reverse order, so finish with ._1.reverse
Edit: attempt to clarify the code (and substitute a test more akin to #elm's to replace the match, too) - hope that makes it clearer what is going on, #Felix! (and no, no offence taken):
def giveFemalesFlowers(people: Seq[Person], flowers: Seq[Flower]): Seq[Person] = {
require(people.count(_.isFemale) == flowers.length)
val start: (List[Person], Seq[Flower]) = (List[Person](), flowers)
val result: (List[Person], Seq[Flower]) = people.foldLeft(start){ (acc, p) =>
val (pList, fList) = acc
if (p.isFemale) {
(p.withFlower(fList.head) :: pList, fList.tail)
} else {
(p :: pList, fList)
}
}
result._1.reverse
}
I'm obviously missing something but isn't it just
people map {
case p if p.isFemale => p.withFlower(f)
case p => p
}
I have List[Int] in Scala. The List is List(1,2,3,4,5,6,7,8,9,10). I want to filter the list so that it only has even numbers. And I want to multiply the numbers with 2.
Is it possible?
As I state in my comment, collect should do what you want:
list.collect{
case x if x % 2 == 0 => x*2
}
The collect method allows you to both specify a criteria on the matching elements (filter) and modify the values that match (map)
And as #TravisBrown suggested, you can use flatMap as well, especially in situations where the condition is more complex and not suitable as a guard condition. Something like this for your example:
list.flatMap{
case x if x % 2 == 0 => Some(x*2)
case x => None
}
A for comprehension (which internally unfolds into a combination of map and withFilter) as follows,
for (x <- xs if x % 2 == 0) yield x*2
Namely
xs.withFilter(x => x % 2 == 0).map(x => x*2)
As #cmbaxter said, collect suits your need perfectly. The other nice thing about collect is that it figures out resulting type in case you're filtering by class:
scala> trait X
// defined trait X
scala> class Foo extends X
// defined class Foo
scala> class Bar extends X
// defined class Bar
scala> val xs = List(new Foo, new Bar, new Foo, new Bar)
// xs: List[X] = List(Foo#4cfa8227, Bar#78226c36, Foo#3f685162, Bar#11f406f8)
scala> xs.collect { case x: Foo => x }
// res1: List[Foo] = List(Foo#4cfa8227, Foo#3f685162)
On par, filter can't be that smart (see List[Foo] vs List[X]):
scala> xs.filter { case x: Foo => true; case _ => false }
// res3: List[X] = List(Foo#4cfa8227, Foo#3f685162)
This should do the work for you:
Filter first when the condition is p % 2 == 0 (for getting only even numbers).
And then use map to multiply those even numbers by 2.
var myList = List(1,2,3,4,5,6,7,8,9,10).filter(p => p % 2 == 0).map(p => {p*2})
I tend to like the filter approach.
val list1 = List(1,2,3,4,5,6,7,8,9,10)
list1.filter(x => x%2 == 0).map(_*2)
How about a good old fashioned fold?
xs.foldLeft(List[Y]()) { (ys, x) =>
val z = calculateSomethingOnX(x)
if (someConditionOnZ(z))
Y(x, z) :: ys
else
ys
}
I read in Programming in Scala section 23.5 that map, flatMap and filter operations can always be converted into for-comprehensions and vice-versa.
We're given the following equivalence:
def map[A, B](xs: List[A], f: A => B): List[B] =
for (x <- xs) yield f(x)
I have a value calculated from a series of map operations:
val r = (1 to 100).map{ i => (1 to 100).map{i % _ == 0} }
.map{ _.foldLeft(false)(_^_) }
.map{ case true => "open"; case _ => "closed" }
I'm wondering what this would look like as a for-comprehension. How do I translate it?
(If it's helpful, in words this is:
take integers from 1 to 100
for each, create a list of 100 boolean values
fold each list with an XOR operator, back into a boolean
yield a list of 100 Strings "open" or "closed" depending on the boolean
I imagine there is a standard way to translate map operations and the details of the actual functions in them is not important. I could be wrong though.)
Is this the kind of translation you're looking for?
for (i <- 1 to 100;
val x = (1 to 100).map(i % _ == 0);
val y = x.foldLeft(false)(_^_);
val z = y match { case true => "open"; case _ => "closed" })
yield z
If desired, the map in the definition of x could also be translated to an "inner" for-comprehension.
In retrospect, a series of chained map calls is sort of trivial, in that you could equivalently call map once with composed functions:
s.map(f).map(g).map(h) == s.map(f andThen g andThen h)
I find for-comprehensions to be a bigger win when flatMap and filter are involved. Consider
for (i <- 1 to 3;
j <- 1 to 3 if (i + j) % 2 == 0;
k <- 1 to 3) yield i ^ j ^ k
versus
(1 to 3).flatMap { i =>
(1 to 3).filter(j => (i + j) % 2 == 0).flatMap { j =>
(1 to 3).map { k => i ^ j ^ k }
}
}