Scala:在一次调用中将相同的功能应用于2个列表

时间:2017-11-09 14:47:53

标签: scala scalaz

让我说

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 part(一些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)

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

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
}

2 个答案:

答案 0 :(得分:3)

您正在寻找foldLeft上的List

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在拼写单元上选择限制性最强的类型而具有攻击性。

答案 1 :(得分:1)

使用Cats的其他方法可以与Tuple2KFoldable 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)))