#scala
#scala
Вопрос:
Мне интересно, каков наилучший способ сохранить начальное состояние массива в scala, чтобы я мог выполнить сброс с начальными значениями после обработки рабочей копии. Я хотел бы сделать что-то вроде этого
val initialValue = Array(Array(1,2,3),Array(4,5,6))
val workingCopy = initialValue.clone
Проблема в том, что когда я изменяю значения workingCopy , я также изменяю значения initialValue .
Я тоже пытался
val workingCopy = Array.fill(2,3)(0)
Array.copy(initialValue,0,workingCopy,2)
Но я получаю тот же результат.
Это справедливо, даже если я использую var
вместо val
при определении массивов. Я думаю, что такое поведение при поверхностном копировании может быть вызвано структурой вложенного массива, но я не уверен, как с этим бороться.
Ответ №1:
Как указал Анджело, обычно вы хотите использовать неизменяемые структуры данных, чтобы избежать подобных проблем. Однако, если вам действительно нужно пойти изменяемым путем, например, по соображениям производительности (хотя «модификация» неизменяемых коллекций, таких как Vector
, не так дорога, как вы думаете), тогда вам нужно сделать глубокую копию ваших вложенных массивов и содержимого. Реализация зависит от вас.
Если это действительно просто an Array[Array[Int]]
, достаточно сделать что-то вроде этого:
val initialValue = Array(Array(1,2,3), Array(4,5,6))
val workingCopy = initialValue.map(_.clone)
Более общий пример с использованием ссылочного типа вместо простого Int
s:
scala> class Cell(var x: String) { def copy = new Cell(x); override def toString = x }
defined class Cell
scala> val initialValue = Array(Array(new Cell("foo")))
initialValue: Array[Array[Cell]] = Array(Array(foo))
scala> val workingCopy = initialValue.map(_.map(_.copy))
workingCopy: Array[Array[Cell]] = Array(Array(foo))
scala> initialValue(0)(0).x = "bar"
initialValue(0)(0).x: String = bar
scala> initialValue
res0: Array[Array[Cell]] = Array(Array(bar))
scala> workingCopy
res1: Array[Array[Cell]] = Array(Array(foo))
Вместо initialValue.map(_.map(_.copy))
этого, конечно, есть другие способы сделать то же самое (например, вложенное for
выражение, которое копирует объекты в качестве побочного эффекта).
Ответ №2:
var
vs val
действительно просто определяет, является ли ссылка неизменяемой, это никак не повлияет на содержимое структуры данных. если бы вы преобразовывали в неизменяемую структуру данных, например a List
, тогда копия была бы ненужной, поскольку операции по «изменению» содержимого такой структуры создают новую ссылку, оставляя оригинал нетронутым.
например:
val initialValue = List(List(1,2,3),List(4,5,6))
val sumInnerLists = initialValue.map(l => l.foldLeft(0)(_ _))
println(sumInnerLists) // List(6, 15)
println(initialValue) // List(List(1,2,3),List(4,5,6))
Комментарии:
1. Я понимаю, что большую часть времени вы хотите использовать неизменяемые структуры данных. Однако мои данные представляют собой действительно большую матрицу, для которой я хочу вызвать рекурсивную функцию, и я не хочу создавать новый объект каждый раз, когда я рекурсивно вызываю функцию или каждый раз передаю ей аргумент (его гораздо дешевле модифицировать на месте).
2. В этом случае вы можете сделать начальное значение неизменяемым списком и преобразовать в массив (или другую изменяемую структуру), чтобы получить свою рабочую копию.