如何使用惯用的Scala替换(填充)来自另一个列表的选项列表中的None条目?
Posted
技术标签:
【中文标题】如何使用惯用的Scala替换(填充)来自另一个列表的选项列表中的None条目?【英文标题】:How to replace(fill) None entries on List of Options from another List using idiomatic Scala? 【发布时间】:2012-06-23 17:49:12 【问题描述】:我有一个List[Option[MyClass]]
和None
在随机位置,我需要从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 来处理该列表?
【问题讨论】:
【参考方案1】:def fillL[T](a:List[Option[T]], b:List[T]) =
val iterB = b.iterator
a.map(_.orElse(Some(iterB.next)))
【讨论】:
【参考方案2】:迭代器解决方案可以说是惯用的 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 旨在允许您以这种方式混合函数式和命令式结构 - 但它确实具有潜在的优势。
【讨论】:
“任何时候你在迭代器上调用 next 时,你都牢牢地处于副作用的境地。”没错,但在这种情况下,它们被巧妙地封装在方法中,保持引用透明。 @Paul:是的,我认为另一种解决方案很棒,这是我选择在我自己的代码中解决这个问题的方法。但它确实涉及副作用,并且在某些类似的情况下可能并不理想。【参考方案3】:我只是以简单的方式编写它,匹配列表的头部并适当地处理每个案例:
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)
大概一旦你用完了可以填满的东西,你就把剩下的 None
s 留在里面。
【讨论】:
以上是关于如何使用惯用的Scala替换(填充)来自另一个列表的选项列表中的None条目?的主要内容,如果未能解决你的问题,请参考以下文章
scala upickle / ujson中JSON null的惯用处理
将 Lambda 应用于返回另一个列表的列表的 Java 8 惯用方法?