Как объявить пустой список, а затем добавить строку в scala?


81

У меня такой код:

val dm  = List[String]()
val dk = List[Map[String,Object]]()

.....

dm.add("text")
dk.add(Map("1" -> "ok"))

но он выдает исключение java.lang.UnsupportedOperationException во время выполнения.

Мне нужно объявить пустой список или пустые карты и кое-где позже в коде нужно их заполнить.


С чего вы взяли, что сейчас addоперация List?
Debilski 02

Если вы хотите использовать операцию добавления, вам нужно будет объявить ArrayList. Vals в scala по сути неизменяемы, поэтому вы не можете их добавлять.
Phantom73 02

1
iirc val больше похож на final, вы можете добавить к ним, если используете изменяемые Коллекции. например, scala-lang.org/api/current/scala/collection/mutable/…
Да Винчи

1
@rjc Какую версию scala вы используете? Mine (2.9.0) выдает ошибку компиляции.
paradigmatic

4
Вы импортировали scala.collection.JavaConversions? Если да, то вы видите именно ту причину, по которой я рекомендую JavaConvertersвместо этого: dmи dkпреобразуются в коллекцию Java, а затем addметод вызывается для этой коллекции. Хуже того , dmи dkне модифицируются, даже если вы не получите сообщение об ошибке. И, кстати, ошибка в том , что 1 -> "ok"это Map[Int,String]не Map[String, Object].
Daniel C. Sobral

Ответы:


117

Списки Scala по умолчанию неизменяемы. Вы не можете «добавить» элемент, но вы можете сформировать новый список, добавив новый элемент впереди. Поскольку это новый список, вам нужно переназначить ссылку (чтобы вы не могли использовать val).

var dm  = List[String]()
var dk = List[Map[String,AnyRef]]()

.....

dm = "text" :: dm
dk = Map(1 -> "ok") :: dk

Оператор ::создает новый список. Вы также можете использовать более короткий синтаксис:

dm ::= "text" 
dk ::= Map(1 -> "ok")

NB: В scala не используйте тип Objectbut Any, AnyRefили AnyVal.


Очень хороший ответ, но можете ли вы сказать, объявляю ли я список, как в вашем ответе, они относятся к типу scala.collections.mutable или неизменяемому? REPL не прояснил это.
rjc 02

2
По умолчанию. Если ничего не импортировать. Listнеизменен. Это рекомендуемый вариант для большинства случаев использования.
paradigmatic

11
@rjc Scala не имеет mutable.List- Listэто конкретный тип, единственная реализация которого неизменна. Существуют неизменяемые классы, такие как LinkedListи DoubleLinkedList, которые в основном являются вспомогательными. Scala эквивалент в Java ArrayListявляется ArrayBuffer, и эквивалент в Java LinkedListесть ListBuffer. Черта , которая соответствует в Java Listесть Seq- из которых есть collection.Seqи, расширяя его, collection.immutable.Seqи collection.mutable.Seq.
Дэниел С. Собрал

@paradigmatic есть ли разница между ::=и +=?
Махди

@ Махди Может быть разница. По спискам только ::определяется, так +=что работать не будет. В другой коллекции (не в стандартной библиотеке): если реализованы ::=или +=, будет использоваться реализация. В противном случае, компилятор превратится x::=yв x = y::xи x+=yИнро x=x+y. Во втором случае они такие же, если реализация ::совпадает с реализацией +...
paradigmatic

17

Если вам нужно мутировать вещи, использование ArrayBufferили LinkedBufferвместо этого. Однако было бы лучше обратиться к этому заявлению:

Мне нужно объявить пустой список или пустые карты и кое-где позже в коде нужно их заполнить.

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

// Fill a list with the results of calls to a method
val l = List.fill(50)(scala.util.Random.nextInt)

// Fill a list with the results of calls to a method until you get something different
val l = Stream.continually(scala.util.Random.nextInt).takeWhile(x => x > 0).toList

// Fill a list based on its index
val l = List.tabulate(5)(x => x * 2)

// Fill a list of 10 elements based on computations made on the previous element
val l = List.iterate(1, 10)(x => x * 2)

// Fill a list based on computations made on previous element, until you get something
val l = Stream.iterate(0)(x => x * 2 + 1).takeWhile(x => x < 1000).toList

// Fill list based on input from a file
val l = (for (line <- scala.io.Source.fromFile("filename.txt").getLines) yield line.length).toList

14

Как уже было сказано, это не лучший способ использования списков в Scala ...

scala> val list = scala.collection.mutable.MutableList[String]()
list: scala.collection.mutable.MutableList[String] = MutableList()

scala> list += "hello"
res0: list.type = MutableList(hello)

scala> list += "world"
res1: list.type = MutableList(hello, world)

scala> list mkString " "
res2: String = hello world

Можете ли вы сказать, объявлен ли ваш список так, как в вашем ответе, даст ли он лучшую производительность во время выполнения по сравнению с парадигметическим ответом? Предположим, что в список будут добавлены миллионы элементов.
rjc 02

Это зависит от того, чего вы пытаетесь достичь. Я бы рекомендовал начать с неизменяемого, как предложил @paradigmatic. Сложность добавления элемента в неизменяемый список list ::= "text"выглядит следующим образом: O (1) является постоянным и лучшим, что вы можете сделать.
agilesteel 02

rjc: минусы неизменяемых списков - O (1); однако, что действительно важно, так это ваш шаблон доступа с точки зрения эффективности. Например, если порядок имеет значение и вы должны создать список путем добавления, Vector - лучший (неизменный) выбор.
Крис Наттикомб 02

6

Как упоминалось в ответе выше , список Scala является неизменной коллекцией. Вы можете создать пустой список с помощью .empty[A]. После этого вы можете использовать метод :+, +:или ::для того , чтобы добавить элемент в список.

scala> val strList = List.empty[String]
strList: List[String] = List()

scala> strList:+ "Text"
res3: List[String] = List(Text)

scala> val mapList = List.empty[Map[String, Any]]
mapList: List[Map[String,Any]] = List()

scala> mapList :+ Map("1" -> "ok")
res4: List[Map[String,Any]] = List(Map(1 -> ok))

2

Коллекции по умолчанию в scala неизменяемы, поэтому у вас есть метод +, который возвращает новый список с добавленным к нему элементом. Если вам действительно нужно что-то вроде метода добавления, вам нужна изменяемая коллекция, например http://www.scala-lang.org/api/current/scala/collection/mutable/MutableList.html, у которой есть метод + =.


0

Возможно, вы можете использовать ListBuffers в scala для создания пустого списка и добавления строк позже, потому что ListBuffers изменяемы. Также все функции List доступны для ListBuffers в scala.

import scala.collection.mutable.ListBuffer 

val dm = ListBuffer[String]()
dm: scala.collection.mutable.ListBuffer[String] = ListBuffer()
dm += "text1"
dm += "text2"
dm = ListBuffer(text1, text2)

если вы хотите, вы можете преобразовать это в список с помощью .toList


0

В вашем случае я использую: val dm = ListBuffer[String]()иval dk = ListBuffer[Map[String,anyRef]]()

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.