首页 > 解决方案 > 如何按值从列表中删除元素?

问题描述

我目前正在研究一个以 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]]返回。

标签: scalalistdictionaryfilterscala-collections

解决方案


你可以使用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))
}

推荐阅读