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

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

Часто времена, когда шаблоны разработки применяются неправильно, это - потому что процесс происходит наоборот. Программист Joe (мои извинения тем из Вас назвали Joe) читает книгу по Шаблонам разработки и говорит "Хорошо, я понимаю Шаблон разработки X, теперь как я могу применить его к своему приложению?" Это неправильно.

Шаблоны разработки могут быть могущественным оружием, но как что-либо еще, они должны использоваться соответственно, и программист должен всегда быть готов включить некоторую исходную мысль в свой дизайн, также.

12
задан Maxime 18 September 2009 в 16:32
поделиться

2 ответа

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

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)

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

6
ответ дан 2 December 2019 в 18:20
поделиться

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

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

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 , вы создаете один новый экземпляр object:

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

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

Теперь l2 даже не относится к тому же типу списка , но ТАКЖЕ ссылается на него! Здесь:

::("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

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

val l6 = list drop 2

Опять же, новый список не создается.

val l7 = list take 1

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

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

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

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

14
ответ дан 2 December 2019 в 18:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: