【问题标题】:Scala - How do I modify an input array passed to a method by reference?Scala - 如何修改通过引用传递给方法的输入数组?
【发布时间】:2020-04-19 06:22:38
【问题描述】:

问题陈述

我将尝试通过一个场景来详细说明这个案例。让我们以这个问题为例。

问题链接:https://leetcode.com/problems/remove-element/

给定一个数组nums 和一个值target,删除所有实例 该值就地并返回新的长度。

不要为另一个数组分配额外的空间,您必须通过 O(1) 额外内存就地修改输入数组来做到这一点。

示例:给定nums = [0,1,2,2,3,0,4,2],target = 2; output = 5(不等于目标的元素数)并将数组修改为 [0,1,3,0,4]

元素的顺序可以改变。你离开什么都没关系 超出新长度。

我的方法

步骤 1:识别与给定目标相等的所有元素,并将它们移动到数组的右侧,同时保持一个计数器。

第 2 步:从右侧删除所有元素。

Step-3:return (n - counter),其中 n 是数组长度,counter 是等于 target 的元素数。

下面是相同的实现:

object RemoveElement {
  // Link to question: https://leetcode.com/problems/remove-element/
  def main(args: Array[String]): Unit = {
    var nums = Array(3,2,2,3)
    val target = 3
    val result = removeElement(nums, target)
    // nums = nums.dropRight(_.equals(target)) // POINT 1
    println(s"Result: ${result}, Modified Array: [${nums.mkString(", ")}]")
  }

  def removeElement(nums: Array[Int], target: Int): Int = {
    val n = nums.length
    var left, counter = 0
    var right = n - 1

    while(left < right){
      if(nums(left) != target){
        left += 1
      }
      else {
        // Find position of the elements which is not equal to target
        if(nums(right) == target){
          counter += 1
          right -= 1
        }
        else{
          // Swap the elements
          counter += 1
          val temp = nums(left)
          nums(left) = nums(right)
          nums(right) = temp
          left += 1
          right -= 1
        }
      } 
    }
    // nums.dropWhile(_.equals(target))  // POINT 2
    // nums = nums.dropRight(_.equals(target))  // POINT 3
    return (n - counter)
  }
}

要点 - 1:绝对有意义,因为数组 nums 在 main 方法的范围内,因此,该语句将作为魅力。

POINT - 2:这些行对数组nums 没有影响。

POINT - 3:给出错误。我知道输入参数(数组nums)的类型为val(即通过引用传递,因此在removeElement 方法的范围内是不可变的)。

如果我可以选择创建一个新数组,那不会有任何问题。但是,如果我需要通过向调用方法添加/删除元素(如在这个问题中)来返回修改后的数组,我该如何在 Scala 中实现呢?

为了使案例更通用,我们可以通过什么方式修改 Scala 方法中的输入集合(作为参数传递)?

P.S.:如果我不从输入数组本身中删除元素,LeetCode 会导致我的提交失败,并显示以下消息:

【问题讨论】:

  • 这里的东西太多了。首先,这些问题非常紧迫,它们可能对学习 Python 、Java 或 C/C++ 等语言有好处,但对 则不然Scala 是一种更具声明性的语言,即使 Scala 允许您在需要(例如在性能很重要时) 时使用命令式,这并不常见,因此,如果您要学习一门语言,最好用地道的方式学习它。
  • 第二,我认为这个问题有点误导,AFAIK Array 是一个固定大小的保留内存量,你不能真正从中删除元素,你可以用零或null 填充多余的空格。但他们必须留在那里。这不仅适用于 Scala,而且适用于任何 JVM 语言。此外,我希望任何母语 (例如 C/C++ 或 Python) 都可以使用相同的方法,但使用malloc 可能会有一些技巧修剪记忆。
  • 真的!但是 Scala 提供了许多功能性能力并在内部为我们处理事情。 drop/dropRight 是为我们做脏活的方法之一。如果必须的话,我只想弄清楚如何在上述问题中描述的情况下进行处理。
  • collections 库中的几乎所有方法都返回修改后的副本,而不是修改原始集合。一些 mutable 集合提供就地修改方法,但这些通常保留用于特殊情况。在 Array 的情况下,这样的dropInPlace 不存在(可能是我在第二条评论中所说的)。最后,即使性能很重要,公开一个修改其输入的公共方法也是很奇怪的。

标签: arrays scala pass-by-reference


【解决方案1】:

如何修改通过引用传递给方法的输入数组?

Scala 不支持按引用传递。默认值是按值传递(或更准确地说,按值传递的一种特殊情况,有时称为按对象调用、按共享调用或按对象共享调用)。 Scala 还支持按名称调用。

所以,您只是不能在 Scala 中通过引用将数组传递给方法。您将不得不使用另一种支持按引用传递的语言,例如 C#(使用 ref 关键字)或 C++。 (请注意,Java 也不支持按引用传递。)

【讨论】:

  • 感谢您的回复。在我的情况下,我应该怎么做才能修改输入数组(从中删除元素)?我可以交换元素。
【解决方案2】:

类似的东西

object Solution {
    def removeElement(nums: Array[Int], `val`: Int): Int = {
      var p: Int = 0
      nums.foreach(v => {
        if (v != `val`) {
          nums(p) = v
          p += 1
        }
      })
      p
    }
}

【讨论】:

    猜你喜欢
    • 2010-09-23
    • 2015-09-12
    • 2015-05-19
    • 2015-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-11
    • 1970-01-01
    相关资源
    最近更新 更多