How to combine filter and map in Scala?
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)
odbhut.shei.chhele
আমাদের এই বাংলাদেশে ছিল তার বাড়ি কাউকে কিছু না বলে অভিমানে দূর দেশে দিল পারি
Updated on July 25, 2022Comments
-
odbhut.shei.chhele almost 2 years
I have
List[Int]
in Scala. The List isList(1,2,3,4,5,6,7,8,9,10)
. I want tofilter
the list so that it only has even numbers. And I want to multiply the numbers with 2.Is it possible?
-
Travis Brown over 8 yearsIt'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
withOption
(which is also just such a common idiom in Scala that it's useful to recognize). -
Travis Brown over 8 yearsI 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 over 8 yearsI have upvoted you. Not I was looking for. THank you.
-
Cacho Santa over 8 years@travisBrown you should give 30 seconds to edit my answer :) I added the explanation now.
-
cmbaxter over 8 years@TravisBrown, good point. I included it as an option in my answer. Thanks.
-
odbhut.shei.chhele over 8 yearsSo what will be the size of my final list, 5 or 10?
-
Travis Brown over 8 years@cacho It's nothing personal, but I also don't think placeholder answers are a particularly good idea. :)
-
cmbaxter over 8 years@eddard.stark, your final list will have a size of 5 when done
-
Cacho Santa over 8 yearsfair enough meta.stackexchange.com/questions/166663/… I never got multiple downvotes so quick, good to know.
-
Sascha Kolberg over 8 yearsThere is also
withFilter
, which, compared tofilter().map()
, avoids one iteration and the creation of a filtered list as intermediate step:list.withFilter(_ % 2 == 0).map(_ * 2)
-
jwvh over 6 yearsHow is this materially different from the answers offered by elm or cacho 2 years ago?
-
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 over 6 yearsBut 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 thefilter
lambda is also curious. -
Adowrath over 6 yearsJust a quick guess, but I think this is because
{ case x: Foo => x }
is typed as aPartialFunction[X, Foo]
.Foo
is the only possible return type, socollect
already knows it has to build a List that can containFoo
s.filter
, on the other hand, does not have such typing knowledge. -
ruloweb almost 6 yearsI think
collect
andwithFilter
are more performant than this,filter
andmap
will iterate the array two times.