将列表拆分为目标元素,列表的其余部分?

时间:2015-11-13 12:42:57

标签: scala playframework functional-programming

假设我有以下内容:

case class Thing(num: Int)

val xs = List(Thing(1), Thing(2), Thing(3))

我想要做的是将列表分成一个特定的值,以及列表的其余部分。目标值可以位于列表中的任何位置,也可以根本不存在。在处理其他值之后,单个值需要单独处理,因此我不能简单地使用模式匹配。

到目前为止我所拥有的是:

val (targetList, rest) = xs.partition(_.num == 2)

val targetEl = targetList match {
    case x :: Nil => x
    case _ => null
}

是否可以将这两个步骤结合起来?像

val (targetEl, rest) = xs.<some_method>

关于处理订单的说明: 必须最后处理目标元素的原因是它用于HTML模板(Play框架)。循环其他元素,并为每个元素呈现HTML元素。在该组元素之后,为目标元素创建另一个HTML元素。

5 个答案:

答案 0 :(得分:3)

可以map中使用模式匹配来完成它,你需要多个案例:

xs map {
    case t @ Thing(1) => // do something with thing 1
    case t => // do something with the other things
}

处理OP的额外要求:

xs map {
    case t @ Thing(num) if(num != 1) => // do something with things that are not "1"
    case t => // do something with thing 1
}

答案 1 :(得分:1)

以下两个列表作为某些条件的元组。

case class Thing(num: Int)

val xs = List(Thing(1), Thing(2), Thing(3))

val partioned = xs.foldLeft((List.empty[Thing], List.empty[Thing]))((x, y) => y match {
  case t @ Thing(1) => (x._1, t :: x._2)
  case t            => (t :: x._1, x._2)
})
//(List(Thing(3), Thing(2)),List(Thing(1)))

答案 2 :(得分:0)

试试这个:

val (targetEl, rest) = (xs.head, xs.tail)

适用于非空列表。无案件必须单独处理。

答案 3 :(得分:0)

经过一些实验,我想出了以下内容,这几乎就是我要找的内容:

rest map <some_method>
maybeTargetEl map <some_other_method>

目标值仍然包含在容器中,但至少它保证单个值。

之后我可以做

var (maybeTargetEl, rest) = xs.
  foldLeft((Option.empty[Thing], ListBuffer[Thing]())){ case ((opt, lb), x) => 
    if (x.num == 1)
      (Some(x), ls)
    else
      (opt, lb += x)
  } match {
    case (opt, lb) => (opt, lb.toList)
  }

如果原始列表的顺序很重要:

{{1}}

答案 4 :(得分:0)

@evanjdooner如果目标元素只出现一次,那么折叠的解决方案就有效。如果您只想提取一个目标元素:

def find(xs: List[T], target: T, prefix: List[T]) = xs match { case target :: tail => (target, prefix ::: tail) case other :: tail => find(tail, target, other :: prefix) case Nil => throw new Exception("Not found") } val (el, rest) = find(xs, target, Nil)

抱歉,我无法将其添加为评论。