5

我在随机位置有一个List[Option[MyClass]]with None,我需要从 a 再次“填充”该列表,以List[MyClass]保持顺序。

以下是示例列表和预期结果:

val listA = List(Some(3),None,Some(5),None,None)
val listB = List(7,8,9)
val expectedList = List(Some(3), Some(7), Some(5), Some(8), Some(9))

那么,如何使用惯用的 Scala 来处理该列表?

4

3 回答 3

13
def fillL[T](a:List[Option[T]], b:List[T]) = {
    val iterB = b.iterator
    a.map(_.orElse(Some(iterB.next)))
}
于 2012-06-21T13:45:32.697 回答
1

迭代器解决方案可以说是惯用的 Scala,并且绝对简洁且易于理解,但它不是功能性的——任何时候调用next迭代器时,你都会牢牢地陷入副作用的境地。

更实用的方法是使用折叠:

def fillGaps[A](gappy: List[Option[A]], filler: List[A]) =
  gappy.foldLeft((List.empty[Option[A]], filler)) {
    case ((current, fs), Some(item)) => (current :+ Some(item), fs)
    case ((current, f :: fs), None) => (current :+ Some(f), fs)
    case ((current, Nil), None) => (current :+ None, Nil)
  }._1

在这里,我们遍历 gappy 列表,同时维护另外两个列表:一个用于我们已处理的项目,另一个用于剩余的填充元素。

这种解决方案不一定比另一种更好——Scala 旨在允许您以这种方式混合函数式和命令式结构——但它确实具有潜在的优势。

于 2012-06-21T16:12:45.887 回答
0

我只是以直截了当的方式编写它,匹配列表的头部并适当地处理每种情况:

def fill[A](l1: List[Option[A]], l2: List[A]) = (l1, l2) match {
  case (Nil, _) => Nil
  case (_, Nil) => l1
  case (Some(x) :: xs, _) => Some(x) :: fill(xs, l2)
  case (None :: xs, y :: ys) => Some(y) :: fill(xs, ys)
}

大概一旦你用完了东西来填充它,你就把剩下的Nones 留在里面。

于 2012-06-21T21:02:41.960 回答