Подтвердить что ты не робот

Как скопировать список в Scala

Я хочу, чтобы мелкий скопировать список в Scala.

Я хотел сделать что-то вроде:

val myList = List("foo", "bar")
val myListCopy = myList.clone

Но метод clone защищен.

4b9b3361

Ответ 1

Чтобы отфильтровать список:

val list = List(1,2,3,4,5)
//only evens
val evens = list.filter(e=>e%2 == 0)

println(list)
//--> List(1, 2, 3, 4, 5)

println(evens) 
//--> List(2, 4)

Вы также можете использовать подстановочный знак для сохранения нескольких символов:

val evens = list.filter(_%2==0)

Обратите внимание, что, как отмечалось выше, списки являются неизменными. Это означает, что эти операции не изменяют исходный список, а фактически создают новый список.

Ответ 2

Здесь нет ответа: не делайте этого. A List является неизменным, поэтому нет абсолютно никакого смысла копировать его.

Рассмотрим несколько операций:

val list = List(1,2,3)
val l1 = 0 :: list
val l2 = "a" :: list

Ни l1, ни l2 не изменяют List, но оба создают новые списки, ссылающиеся на List.

Объясним это подробно. Конструктор List(1,2,3) создает три элемента и использует один и тот же объект. В частности, он создает эти элементы:

::(3, Nil)
::(2, reference to the previous element)
::(1, reference to the previous element)

И Nil - одноэлементный объект. То, что на самом деле указывает идентификатор List, это последний элемент.

Теперь, когда вы назначаете 0 :: list на l1, вы создаете экземпляр одного нового объекта:

::(0, reference to ::(1, etc))

Конечно, поскольку есть ссылка на List, вы можете представить l1 как список из четырех элементов (или пять, если вы считаете Nil).

Теперь l2 даже не того же типа List, но он также ссылается на него! Здесь:

::("a", reference to ::(1, etc))

Важным моментом во всех этих объектах является то, что они не могут быть изменены. Нет никаких сеттеров, ни каких-либо методов, которые бы изменили любые их свойства. Они будут навсегда иметь одинаковые значения/ссылку в своей "голове" (то, что мы называем первым элементом), и те же ссылки в их "хвосте" (что мы называем вторым элементом).

Однако есть методы, которые выглядят так, как будто они меняют список. Будьте уверены, однако, что они создают новые списки. Например:

val l3 = list map (n => n + 1)

Карта метода создает совершенно новый список того же размера, где новый элемент может быть вычислен из соответствующего элемента в List (но вы также можете игнорировать старый элемент).

val l4 = l2 filter (n => n.isInstanceOf[Int])

Хотя l4 имеет те же элементы, что и List (но другой тип), это также совершенно новый список. Метод filter создает новый список, основанный на правиле, которое вы передаете, чтобы сообщить ему, какие элементы входят, а какие нет. Он не пытается оптимизировать, если он может вернуть существующий список.

val l5 = list.tail

Это не создает новый список. Вместо этого он просто присваивает l5 существующий элемент List.

val l6 = list drop 2

Снова не создается новый список.

val l7 = list take 1

Это, однако, создает новый список именно потому, что он не может изменить первый элемент List так, чтобы его хвост указывал на Nil.

Вот несколько дополнительных деталей реализации:

  • List - абстрактный класс. Он имеет два потомка, класс :: (да, это имя класса) и одноэлементный объект Nil. List запечатан, поэтому вы не можете добавлять к нему новые подклассы, а :: является окончательным, поэтому вы не можете подклассифицировать его.

  • Пока вы ничего не можете изменить для изменения списка, он использует изменчивое состояние внутри некоторых операций. Это помогает в производительности, но локализовано таким образом, что никакая программа, которую вы пишете, никогда не сможет ее обнаружить или получить от нее последствия. Вы можете передавать списки по своему усмотрению, независимо от того, что с ними делают другие функции, или сколько потоков использует их одновременно.