How to combine filter and map in Scala?

30,797

Solution 1

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
}

Solution 2

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)

Solution 3

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)

Solution 4

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})

Solution 5

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)
Share:
30,797
odbhut.shei.chhele
Author by

odbhut.shei.chhele

আমাদের এই বাংলাদেশে ছিল তার বাড়ি কাউকে কিছু না বলে অভিমানে দূর দেশে দিল পারি

Updated on July 25, 2022

Comments

  • odbhut.shei.chhele
    odbhut.shei.chhele almost 2 years

    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?

  • Travis Brown
    Travis Brown over 8 years
    It's not always possible or convenient to phrase your condition in such a way that it will work as a guard, so (IMO) a good answer should include flatMap with Option (which is also just such a common idiom in Scala that it's useful to recognize).
  • Travis Brown
    Travis Brown over 8 years
    I tend to downvote all code-only answers that I see, but the "How to combine" part of the title means that this isn't even really an answer.
  • odbhut.shei.chhele
    odbhut.shei.chhele over 8 years
    I have upvoted you. Not I was looking for. THank you.
  • Cacho Santa
    Cacho Santa over 8 years
    @travisBrown you should give 30 seconds to edit my answer :) I added the explanation now.
  • cmbaxter
    cmbaxter over 8 years
    @TravisBrown, good point. I included it as an option in my answer. Thanks.
  • odbhut.shei.chhele
    odbhut.shei.chhele over 8 years
    So what will be the size of my final list, 5 or 10?
  • Travis Brown
    Travis Brown over 8 years
    @cacho It's nothing personal, but I also don't think placeholder answers are a particularly good idea. :)
  • cmbaxter
    cmbaxter over 8 years
    @eddard.stark, your final list will have a size of 5 when done
  • Cacho Santa
    Cacho Santa over 8 years
    fair enough meta.stackexchange.com/questions/166663/… I never got multiple downvotes so quick, good to know.
  • Sascha Kolberg
    Sascha Kolberg over 8 years
    There is also withFilter, which, compared to filter().map(), avoids one iteration and the creation of a filtered list as intermediate step: list.withFilter(_ % 2 == 0).map(_ * 2)
  • jwvh
    jwvh over 6 years
    How is this materially different from the answers offered by elm or cacho 2 years ago?
  • Dean Sha
    Dean Sha over 6 years
    @jwvh thanks for the comment. It is a slightly different approach. It's a matter of preference that's why I used the phrase "tend to like". I posted the response now because I had this question too and thought others in future have the benefit of looking at different options.
  • jwvh
    jwvh over 6 years
    But it's not a different option. It's exactly the same as cacho's suggestion. The only difference is the use of the underscore in the map lambda. Why you don't do the same in the filter lambda is also curious.
  • Adowrath
    Adowrath over 6 years
    Just a quick guess, but I think this is because { case x: Foo => x } is typed as a PartialFunction[X, Foo]. Foo is the only possible return type, so collect already knows it has to build a List that can contain Foos. filter, on the other hand, does not have such typing knowledge.
  • ruloweb
    ruloweb almost 6 years
    I think collect and withFilter are more performant than this, filter and map will iterate the array two times.