2009-09-18 3 views
12

Я хочу, чтобы скопировать список в Scala.Как скопировать список в Scala

Я хотел сделать somehing как:

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

Но метод клонирования защищен.

+0

Не будет ли это быть связано с http://stackoverflow.com/questions/1267261/does-scala-anyref-clone-perform-a-shallow-or-deep-copy? – VonC

+12

Зачем? Объекты списка неизменяемы. –

+1

Я хотел удалить элемент из списка (используя метод remove (A => Boolean)) в цикле. (Примечание: я начал Scala 2 часа назад :)) – Maxime

ответ

6

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

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) 

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

13

Вот не ответ: не делайте этого. 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 запечатан, поэтому вы не можете добавлять к нему новые подклассы, а :: является окончательным, поэтому вы не можете подклассифицировать его.

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

Смежные вопросы