【问题标题】:Scala: Apply same function to 2 lists in one callScala:一次调用将相同的功能应用于 2 个列表
【发布时间】:2017-11-09 14:47:53
【问题描述】:

假设我有

val list: List[(Int, String)] = List((1,"test"),(2,"test2"),(3,"sample"))

我需要根据 (Int, String) 值将此列表分成两部分。到现在为止还挺好。 例如它可以是

def isValid(elem: (Int, String)) = elem._1 < 3 && elem._2.startsWith("test")
val (good, bad) = list.partition(isValid)

所以,现在我有 2 个带有签名 List[(Int, String)] 的列表,但我只需要 Int 部分(一些 id)。当然我可以写一些函数

def ids(list:List(Int, String)) = list.map(_._1)

并在两个列表中调用它

val (ok, wrong) = (ids(good), ids(bad))

它有效,但看起来有点样板。我更喜欢类似的东西

val (good, bad) = list.partition(isValid).map(ids)

但这显然是不可能的。那么有没有“更好”的方式来做我需要的事情? 我知道这并没有那么糟糕,但觉得对于这种情况存在一些功能模式或通用解决方案,我想知道它:)谢谢!

附:谢谢大家!最后变成了

private def handleGames(games:List[String], lastId:Int) = {
  val (ok, wrong) = games.foldLeft(
  (List.empty[Int], List.empty[Int])){
    (a, b) => b match {
      case gameRegex(d,w,e) => {
        if(filterGame((d, w, e), lastId)) (d.toInt :: a._1, a._2)
        else (a._1, d.toInt :: a._2 )
      }
      case _ => log.debug(s"not handled game template is: $b"); a
    }
  }
  log.debug(s"not handled game ids are: ${wrong.mkString(",")}")
  ok
}

【问题讨论】:

  • 老实说,除非有性能问题,否则我只会使用两个maps。然后我会使用fold

标签: scala scalaz


【解决方案1】:

您正在List 上寻找foldLeft

myList.foldLeft((List.empty[Int], List.empty[Int])){
  case ((good, bad), (id, value)) if predicate(id, value) => (id :: good, bad)
  case ((good, bad), (id, _)) => (good, id :: bad)
}

通过这种方式,您可以在每个阶段进行转换和累积操作。返回的类型将是 (List[Int], List[Int]) 假设 predicate 是在“好”和“坏”状态之间选择的函数。 Nil 的演员表是由于 Scala 在选择 foldl 上最具限制性的类型方面的激进性质。

【讨论】:

  • 谢谢,小麦。我同意你的看法,它更实用。但是,我认为纯函数式风格不太可读的情况很少见,可能我会使用我的代码......
  • 那我改用empty。也许这会更具可读性?
  • 嗯,这更好,但强制转换为 Nil 并不是最复杂的事情。经过一番思考,我使用了你的建议(但它比我之前问的更复杂)。我选择了它,主要是因为在这种情况下它只是一次通过集合,但是我仍然对语法不满意。我将在问题中添加最终代码
【解决方案2】:

另一种使用 Cats 的方法可以与 Tuple2KFoldables foldMap 一起使用。请注意,这需要 kind-projector 编译器插件的帮助

import cats.implicits._
import cats.Foldable
import cats.data.Tuple2K

val listTuple = Tuple2K(list, otherList)
val (good, bad) = Foldable[Tuple2K[List, List, ?]].foldMap(listTuple)(f =>
  if (isValid(f)) (List(f), List.empty) else (List.empty, List(f)))

【讨论】:

  • 您应该注意这一点,因为您也在使用类型投影仪插件。这是Foldable 类型参数中的非标准Scala 语法。
  • 这很有趣,但对于有过 OOP 经验的人来说,情况就更加复杂了。我试图尽可能使用函数式构造,但在这种情况下,我更喜欢使用简单的代码
猜你喜欢
  • 1970-01-01
  • 2014-05-29
  • 2020-12-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-11
相关资源
最近更新 更多