【问题标题】:Scala: Fill the gaps in a List with last non-empty valueScala:用最后一个非空值填充列表中的空白
【发布时间】:2016-01-27 12:29:15
【问题描述】:

我有一个类似的列表:

val arr = Array("a", "", "", "b", "c", "")

我正在寻找一种创建方式:

Array("a", "a", "a", "b", "c", "c")

【问题讨论】:

  • 你试过什么?这并不难。如果列表的第一个元素是“”,那么期望的输出是什么?
  • 我试过这个:var temp = ""; arr.map{ v => if(v!="") { temp=v; v } 其他临时 }。这是最优雅的方式吗?
  • @Mohitt 我知道你想用他们左边邻居的值来完成洞(空字符串)。不是吗?
  • @PabloFranciscoPérezHidalgo,是的。我试过这个: var temp = "" arr.map{ case "" => { temp };案例 v => {temp=v; v } }。我正在寻找更优雅的方式。
  • 如果Array的第一个元素为空怎么办?应该使用什么值?

标签: scala collections


【解决方案1】:

您可以尝试使用折叠,简单(易于理解)的方法是向左折叠:

(Array.empty[String] /: arr) {
    case (prev, "") => prev :+ prev.lastOption.getOrElse("");
    case (prev, l) => prev :+ l
}

> res01: Array[String] = Array(a, a, a, b, c, c)

这会根据源元素是否为空字符串,通过附加 arr 元素或结果列表的最后一个元素来构建一个新数组。

你也可以这样写:

(Array.empty[String] /: arr) {
    case (Array(), l) => Array(l)
    case (prev, "") => prev :+ prev.last;
    case (prev, l) => prev :+ l
}

可以通过使用列表和前置来优化:

{(List.empty[String] /: arr) {
    case (Nil, l) => l::Nil
    case (h::tail, "") => h::h::tail;
    case (prev, l) => l::prev
} reverse } toArray

如果您不喜欢 fold left 和 fold right 方法的符号版本。这里带有它的文本标识符:

arr.foldLeft(Array.empty[String]) {
    case (prev, "") => prev :+ prev.lastOption.getOrElse("");
    case (prev, l) => prev :+ l
}

arr.foldLeft(List.empty[String]) {
    case (Nil, l) => l::Nil
    case (h::tail, "") => h::h::tail;
    case (prev, l) => l::prev
}.reverse toArray

它的方法和实现完全相同,但名称不同。

【讨论】:

  • 使用 /: 肯定不是 Scala 惯用的。 Another example, where I have doubts if not regrets are the /: and :\ operators in scala.collections. They are cute synonyms for folds, and I am still fond of the analogy with falling dominoes they evoke. But in retrospect I think maybe they did give a bad example for others to go overboard with symbolic operators. - Odersky
  • @KevinMeredith 它的“一个坏例子”本身还不错,但我会编辑我的答案以包含文本版本。我不会说这不是惯用的。
  • 嘿巴勃罗 - 谢谢。另外,我应该说not idiomatic [in my opinion],指着奥德斯基的那篇帖子来支持我的论点。
  • @KevinMeredith 他喜欢它,但遗憾的是它成为了一个暗示符号运算符是首选的例子,在某些情况下,这会导致滥用符号标识符;P 没问题,只是这样我已经并获得了:` and 的品味:/`
【解决方案2】:

不确定这是否是一种优雅的方式,但想出了一个解决方案:

var temp = "" 
arr.map{ case "" => { temp }; case v => {temp=v; v } }

【讨论】:

  • 它立即解决了问题,所以它是一个很好的解决方案,但是它是一个命令式的解决方案,也就是说,在它呈现副作用的意义上不是纯粹的。根据您的程序上下文,这可能会成为错误的来源。例如:如果有人在未来的提交中在第一行和第二行之间插入更改temp 的代码怎么办?
【解决方案3】:

我认为 Mohitt 的回答是一个明确的解决方案……但 Pablo Francisco Pérez Hidalgo 是对的,它有副作用

也许我们可以在函数中包含变量以避免其他开发人员更改临时变量

(x: Array[String]) => { var last = ""; x.map { v => if (v != "") last = v; last } }

这样使用:

val fillEmpty = (x: Array[String]) => { var last = ""; x.map { v => if (v != "") last = v; last } }
fillEmpty(arr)

【讨论】:

    猜你喜欢
    • 2021-10-25
    • 2019-11-21
    • 2015-07-22
    • 2021-10-15
    • 2015-09-17
    • 2017-07-19
    • 1970-01-01
    • 2017-08-08
    • 1970-01-01
    相关资源
    最近更新 更多