在Scala中收集嵌套列表子代的最简洁方法是什么?

时间:2016-10-06 16:49:02

标签: scala

想象一下,我有一个3级或更多级别的嵌套列表(或任何其他集合),例如

val items: Seq[Seq[Seq[Int]]] = Seq(Seq(Seq(1,2,3), Seq(4,5,6), Seq(4,5,6)), Seq(Seq(1,2,3), Seq(4,5,6), Seq(4,5,6)))

根据布尔规则遍历此集合并收集子节点的最简洁方法是什么。

如给出以下规则

(item) => item % 2 == 0

返回

 Seq(2,4,6,4,6,2,4,6,4,6)

没有平铺/展平列表或使用可变集合!

2 个答案:

答案 0 :(得分:3)

前一段时间,有人问了一个关于嵌套Option的类似问题。我提供了一个通用的解决方案模式,它适用于任何monadic结构。

请确保您拥有嵌套的monadic类型......它不适用于Seq [Any]

我将扩展它以处理Seq

import scala.language.higherKinds

case class Flattener[W[_], WW, T](fn : WW => W[T])

implicit def seqRecFlattenFn[WW, T](
  implicit f: Flattener[Seq, WW, T] = Flattener((ww: WW) => Seq(ww))
) = Flattener((ww: Seq[WW]) => ww.flatMap(f.fn))

def seqRecursiveFlatten[WW, T](www: Seq[WW])(
  implicit f : Flattener[Seq, Seq[WW], T]
) = f.fn(www)

val nestedSeq1 = Seq(Seq(Seq(Seq(5, 10), Seq(20, 30))))
// nestedSeq1: Seq[Seq[Seq[Seq[Int]]]] = List(List(List(List(5, 10), List(20, 30))))

val flatSeq1 = seqRecursiveFlatten(nestedSeq1)
// flatSeq1: Seq[Int] = List(5, 10, 20, 30)

val nestedSeq2 = Seq(Seq(Seq(Seq(Seq(Seq(Seq(5, 10), Seq(20, 30)))))))
// nestedSeq2: Seq[Seq[Seq[Seq[Seq[Seq[Seq[Int]]]]]]] = List(List(List(List(List(List(List(5, 10), List(20, 30)))))))

val flatSeq2 = seqRecursiveFlatten(nestedSeq)
// flatSeq2: Seq[Int] = List(5, 10, 20, 30)

现在你有一个平坦的Seq,所以应用任何过滤或你想要的任何东西。

答案 1 :(得分:0)

如果您需要处理任意嵌套列表,那么您必须处理Seq [Any]:

def flatFilter(src: Seq[Any], pred: (Int => Boolean)): Seq[Int] = {
  if (src.isEmpty) 
    Seq.empty
  else src.head match {
    case car: Seq[Any] =>
      flatFilter(car, pred) ++ flatFilter(src.tail, pred)
    case car: Int =>
      if (pred(car)) 
        car +: flatFilter(src.tail, pred)
      else 
        flatFilter(src.tail, pred)
    case _ => flatFilter(src.tail, pred)
  }
}