Scala:在一次调用中将相同的函数应用于 2 个列表
Scala: Apply same function to 2 lists in one call
假设我有
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)
但这显然不可能。那么有 "Nicer" 方法来做我需要的吗?
我知道这还不错,但觉得对于这种情况存在一些功能模式或通用解决方案,我想知道:)谢谢!
P.S。谢谢大家!最后转化为
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
}
您正在 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
是在 "good" 和 "bad" 状态之间选择的函数。 Nil
的转换是由于 Scala 在 foldl 上选择最严格类型的激进性质。
另一种使用猫的方法可以与 Tuple2K
和 Foldable
s 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)))
假设我有
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)
但这显然不可能。那么有 "Nicer" 方法来做我需要的吗? 我知道这还不错,但觉得对于这种情况存在一些功能模式或通用解决方案,我想知道:)谢谢!
P.S。谢谢大家!最后转化为
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
}
您正在 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
是在 "good" 和 "bad" 状态之间选择的函数。 Nil
的转换是由于 Scala 在 foldl 上选择最严格类型的激进性质。
另一种使用猫的方法可以与 Tuple2K
和 Foldable
s 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)))