How to combine filter and map in scala?

2020-02-24 13:06发布

问题:

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 muliply the numbers with 2. Is it possible?

I hope I have explained the question clearly. If u have any questions then please ask. THanks in advance.

回答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
}


回答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)


回答3:

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


回答4:

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)


回答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)


回答6:

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
}