如何按值从列表中删除元素?

时间:2019-11-19 06:07:22

标签: scala list dictionary filter scala-collections

我目前正在研究一个以Map [String,List [String]]和一个String作为参数的函数。该地图包含用户ID和他们喜欢的电影的ID。我需要做的是,返回一个List [List [String]],其中包含其他喜欢传递给函数的电影的用户所喜欢的电影。

函数声明如下:

def movies(m: Map[String, List[String]], mov: String) : List[List[String]]= {

}

因此,请想象以下内容:

val m1 : [Map[Int, List[String]]] = Map(1 ‐> List("b", "a"), 2 ‐> List("y", "x"), 3 ‐> List("c", "a"))
val movieID = "a"
movies(m1, movieId)

这应该返回:

List(List("b"), List("c"))

我尝试使用

m1.filter(x => x._2.contains(movieID))

因此,只有包含movieID的列表保留在地图中,但是我的问题是我需要从其中出现的每个列表中删除movieID,然后将结果作为List [List [String]]返回。

3 个答案:

答案 0 :(得分:2)

您可以使用collect

val m = Map("1" -> List("b", "a"), "2" -> List("y", "x"), "3" -> List("c", "a"))

def movies(m: Map[String, List[String]], mov: String) = m.collect {
  case (_, l) if l.contains(mov) => l.filterNot(_ == mov)
}

movies(m, "a") //List(List(b), List(c))

此方法的问题是,它将对每个电影列表进行两次迭代,第一次使用contains,第二次使用filterNot。我们可以优化它的尾递归函数,该函数将查找元素,如果找到,则返回不包含它的列表:

import scala.annotation.tailrec

def movies(m: Map[String, List[String]], mov: String) = {

   @tailrec
   def withoutElement[T](l: List[T], mov: T, acc: List[T] = Nil): Option[List[T]] = {
      l match {
        case x :: xs if x == mov => Some(acc.reverse ++ xs)
        case x :: xs => withoutElement(xs, mov, x :: acc)
        case Nil => None
      }
   }

   m.values.flatMap(withoutElement(_, mov))
}

答案 1 :(得分:1)

Krzysztof的解决方案很好。这是另一种遍历每个List一次的方法。

def movies(m: Map[String, List[String]], mov: String) =
  m.values.toList.flatMap{ss =>
    val tpl = ss.foldLeft((false, List.empty[String])){
      case ((_,res), `mov`)  => (true, res)
      case ((keep,res), str) => (keep, str::res)
    }
    if (tpl._1) Some(tpl._2) else None
  }

答案 2 :(得分:1)

这应该对您有用:

  object DemoAbc extends App {
  val m1 = Map(1 -> List("b", "a"), 2 -> List("y", "x"), 3 -> List("c", "a"))
  val movieID = "a"

  def movies(m: Map[Int, List[String]], mov: String): List[List[String]] = {
    val ans = m.foldLeft(List.empty[List[String]])((a: List[List[String]], b: (Int, List[String])) => {
      if (b._2.contains(mov))
        b._2.filter(_ != mov) :: a
      else a
    })

    ans
  }

  print(movies(m1, movieID))
}