【问题标题】:Scala for/yield syntaxScala for/yield 语法
【发布时间】:2014-05-10 12:15:59
【问题描述】:

在我正在学习的书中有一个练习:

编写一个循环,交换整数数组的相邻元素。例如,Array(1,2,3,4,5) 变为 Array(2,1,4,3,5)。我的解决方案是:

var v = Array(0,1,2,3,4,5,6,7,8,9)
for (i <- 0 until v.length by 2) {
  var temp = 0
  temp = v(i+1); v(i+1) = v(i); v(i) = temp
}

这个算法运行良好,但没有充分利用 Scala 的潜力,它的编写就像我用 C++ 编写的一样。事实上,下面的练习要求:

重复前面的赋值,但是用交换后的值生成一个新数组。使用 for/yield

现在我尝试了:

val a = ArrayBuffer(1,2,3,4,5)
var res = for (i <- 0 until a.length by 2) yield a(i)
for (i <- 1 until a.length by 2) res(i-1)=a(i) <---------eclipse give me an error

错误是:“value update is not a member of scala.collection.immutable.IndexedSeq[Int]

我该如何解决这个任务?我知道“for/yield”这个语法很强大,但是不知道怎么用。

【问题讨论】:

  • 这个错误是因为res是一个不可变的序列(一个向量),不能就地更新。 Vector 确实有一个 updated(index: Int, elem: A) 方法,但是,它返回一个带有更新元素的新 Vector。
  • a 是一个 ArrayBuffer,所以 res 也会自动成为一个 ArrayBuffer。对吗?
  • 不,它没有 - 试试看!如果您执行for (i &lt;- a) yield i 之类的操作,它将变为ArrayBuffer,其中a 是for-comprehension 中的起始集合。

标签: scala for-loop yield


【解决方案1】:

有一个 sliding 函数可以满足您的需要:

(for {
  i <- Array(1,2,3,4,5).sliding(2,2)
  j <- i.reverse
} yield j).toArray

【讨论】:

  • 或者单行但不是for循环:Array(1,2,3,4,5).sliding(2,2).flatMap(_.reverse).toArray
  • 你能详细解释一下你写的代码吗?滑动函数我懂,但是为什么要两个索引(i和j)?
  • i&lt;- Array(1,2,3,4,5).sliding(2,2) spawns: Array(Array(1, 2), Array(3, 4), Array(5)) i 迭代内部数组。现在你需要反转它们并且你需要一个名字,所以你只需给它一个j作为名字。为了更好地理解在谷歌上的理解搜索它们是如何扩展的。这些实际上是一系列平面地图、地图和过滤器。在这里阅读更多:stackoverflow.com/questions/14598990/…
【解决方案2】:

我自己正在使用 Scala for the Impatient 来更新我的 Scala 编码技能。鉴于书中这一点介绍的概念,我相信作者正在寻找以下内容:

val a = Array(1, 2, 3, 4, 5)
for (i <- 0 until a.length) 
  yield 
    if (i % 2 == 0) 
      if (i == a.length-1) a(i) 
      else a(i+1) 
    else a(i-1)

【讨论】:

    【解决方案3】:

    在您的生成器中,您使用0 until v.length by 2,即IndexedSeq。这是您的输入类型,yield 将为res 生成相同的集合类型。

    由于immutable.IndexedSeq 是不可变的,您无法修改它。因此,res(i-1)=a(i) 将在 i-1 处更新项目是不允许的。

    因此,一种选择是在继续之前将 res 转换为可变集合。

    一个通常更可取的选择是在不更新的情况下解决它。这里是使用foldLeftexample,它迭代我们的IndexedSeq 并构建一个新的扁平化Array[Int]

    val array = Array(1,2,3,4,5)
    
    val result = (
        for ( i <- 0 until array.length by 2) 
        yield 
            if (i < array.length-1) 
                Array(array(i+1), array(i)) 
            else 
                Array(array(i))
    ).foldLeft (Array[Int]()) ((a,b) => a ++ b )
    

    【讨论】:

    • 这段代码工作正常,就像其他用户发布的其他代码一样,但我还不太明白。你能给我解释一下吗? yield 之后的结构 if()...else() 决定了我认为的结果值。但是 .foldLeft 呢?
    • 您可能有兴趣阅读 Haskell 的 folds。 Haskell 是一种函数式语言,在某些方面与 Scala 相似。我建议阅读 Haskell 对折叠的描述,因为有关 Haskell 的信息很容易以一种很好的、​​易于理解的格式找到。我很难了解 Scala 的信息。通过这种方式,您可能能够大致了解折叠的作用。
    【解决方案4】:

    错误是因为res 是不可变序列(向量),无法就地更新。 Vector 确实有一个 updated(index: Int, elem: A) 方法,但是,它返回一个带有更新元素的新 Vector。

    我不确定这个练习的作者是怎么想的 - 在这里使用 for/yield 似乎有点尴尬,但你可以使用 grouped():

    val a = Array(1,2,3,4,5)            //> a  : Array[Int] = Array(1, 2, 3, 4, 5)
    
    val swapped = (for (i <- a.grouped(2)) yield i.reverse).flatten.toArray            
                                  //> swapped  : Array[Int] = Array(2, 1, 4, 3, 5)
    

    没有 for/yield 的更简洁的方式,使用 flatMap 也是可能的

    a.grouped(2).toArray.flatMap(_.reverse)                                      
                                       //> res5: Array[Int] = Array(2, 1, 4, 3, 5)
    

    【讨论】:

      【解决方案5】:

      只是一种新方法:

      (for (i<-0 to arr.length-2 by 2) yield Array(arr(i+1), arr(i))).flatten.toArray
      

      【讨论】:

        【解决方案6】:

        这是我的解决方案:

        def swap(a: Array[Int]): Array[Int] = {
            for (elem <- 0 until a.length)
              yield {
                if (elem % 2 == 0) {
                  if (elem == a.length - 1) a(elem)
                  else a(elem + 1)
                }
                else a(elem - 1)
              }
          }.toArray
        

        【讨论】:

          【解决方案7】:
          var result = for(j<- 0 until (a.length,2);
          i<- 1 to 0 by -1; 
          if (j+i < a.length) )  
             yield a(j+i)
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-04-26
            • 2016-02-12
            • 2016-05-10
            • 2016-07-21
            • 2015-03-01
            相关资源
            最近更新 更多