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

81

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

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

.....

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

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

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

rjc
источник
С чего вы взяли, что сейчас 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]]()

ПЗУ
источник