Wie deklariere ich eine leere Liste und füge dann einen String in die Scala ein?

79

Ich habe folgenden Code:

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

.....

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

Es wird jedoch die Laufzeit java.lang.UnsupportedOperationException ausgelöst.

Ich muss eine leere Liste oder leere Karten deklarieren und einige, wo später im Code sie füllen müssen.

rjc
quelle
Was lässt Sie denken, dass es eine addOperation gibt List?
Debilski
Wenn Sie die Add-Operation verwenden möchten, müssen Sie eine ArrayList deklarieren. Vals in Scala sind im Wesentlichen unveränderlich, daher können Sie sie nicht ergänzen.
Phantom73
1
iirc val ist eher final, Sie können es ergänzen, wenn Sie die veränderlichen Sammlungen verwenden. zB scala-lang.org/api/current/scala/collection/mutable/…
DaVinci
1
@rjc Welche Version von Scala verwenden Sie? Meins (2.9.0) gibt mir einen Kompilierungsfehler.
Paradigmatisch
4
Hast du importiert scala.collection.JavaConversions? Wenn Sie dies getan haben, sehen Sie genau den Grund, warum ich JavaConvertersstattdessen empfehle : dmund dkwerden in eine Java-Sammlung konvertiert, und dann die addMethode, die für diese Sammlung aufgerufen wird. Schlimmer noch dmund dkwerden nicht geändert, auch wenn Sie keinen Fehler erhalten haben. Übrigens ist der Fehler, dass dies nicht der Fall 1 -> "ok"ist . Map[Int,String]Map[String, Object]
Daniel C. Sobral

Antworten:

116

Scala-Listen sind standardmäßig unveränderlich. Sie können kein Element "hinzufügen", aber Sie können eine neue Liste erstellen, indem Sie das neue Element davor anhängen. Da es sich um eine neue Liste handelt, müssen Sie die Referenz neu zuweisen (damit Sie keinen Wert verwenden können).

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

.....

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

Der Bediener ::erstellt die neue Liste. Sie können auch die kürzere Syntax verwenden:

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

NB: Verwenden Sie in Scala nicht den Typ Objectaber Any, AnyRefoder AnyVal.

paradigmatisch
quelle
Sehr gute Antwort, aber können Sie sagen, ob ich eine Liste wie in Ihrer Antwort deklariere, ob sie vom Typ scala.collections.mutable oder unveränderlich sind? REPL hat dies nicht klargestellt.
rjc
2
Standardmäßig. Wenn Sie nichts importieren. Listist unveränderlich. Dies ist die empfohlene für die meisten Anwendungen.
Paradigmatisch
11
@rjc Scala hat kein mutable.List- Listist ein konkreter Typ, dessen einzige Implementierung unveränderlich ist. Es gibt unveränderliche Klassen wie LinkedListund DoubleLinkedList, die meistens Hilfsklassen sind. Das Scala-Äquivalent von Java ArrayListist ArrayBufferund das Äquivalent von Java LinkedListist ListBuffer. Das Merkmal, das Java entspricht, Listist Seq- von dem es gibt collection.Seqund erweitert, collection.immutable.Seqund collection.mutable.Seq.
Daniel C. Sobral
@paradigmatic gibt es einen Unterschied zwischen ::=und +=?
Mahdi
@ Mahdi Es kann einen Unterschied geben. Nur auf Listen ::ist definiert, +=funktioniert also nicht. Bei anderer Sammlung (nicht in der Standardbibliothek): Wenn ::=oder +=implementiert sind, wird die Implementierung verwendet. Andernfalls wird der Compiler x::=yzu x = y::xund x+=yinro x=x+y. Im zweiten Fall sind sie gleich, wenn die Implementierung von ::die gleiche ist wie die Implementierung von +...
paradigmatisch
17

Wenn Sie etwas mutieren müssen, verwenden Sie ArrayBufferoder LinkedBufferstattdessen. Es wäre jedoch besser, diese Aussage anzusprechen:

Ich muss eine leere Liste oder leere Karten deklarieren und einige, wo später im Code sie füllen müssen.

Füllen Sie stattdessen die Liste mit Code, der die Elemente zurückgibt. Es gibt viele Möglichkeiten, dies zu tun, und ich werde einige Beispiele nennen:

// 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
Daniel C. Sobral
quelle
14

Wie bereits erwähnt, ist dies nicht die beste Möglichkeit, Listen in Scala zu verwenden ...

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
agilesteel
quelle
Können Sie feststellen, ob Ihre Liste wie in Ihrer Antwort deklariert ist? Wird sie eine bessere Laufzeitleistung bieten als eine paradigmatische Antwort? Angenommen, Millionen von Elementen würden der Liste hinzugefügt.
rjc
Es hängt davon ab, was Sie erreichen wollen. Ich würde empfehlen, mit einem unveränderlichen zu beginnen, wie @paradigmatic vorgeschlagen hat. Die Komplexität des Hinzufügens eines Elements zu einer unveränderlichen Liste wie list ::= "text"folgt ist O (1), was konstant ist und das Beste ist, was Sie tun können.
Agilesteel
rjc: Nachteile unveränderlicher Listen sind O (1); Was jedoch wirklich zählt, ist Ihr Zugriffsmuster in Bezug auf die Effizienz. Wenn beispielsweise die Reihenfolge wichtig ist und Sie die Liste durch Anhängen erstellen müssen, ist Vector eine bessere (unveränderliche) Wahl.
Kris Nuttycombe
6

Wie in einer obigen Antwort erwähnt , ist die Scala-Liste eine unveränderliche Sammlung. Sie können eine leere Liste mit erstellen .empty[A]. Dann können Sie eine Methode verwenden :+, +:oder ::um Element in die Liste hinzuzufügen.

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))
Gihanchanuka
quelle
0

Vielleicht können Sie ListBuffers in Scala verwenden, um eine leere Liste zu erstellen und später Zeichenfolgen hinzuzufügen, da ListBuffers veränderbar sind. Außerdem sind alle List-Funktionen für die ListBuffers in Scala verfügbar.

import scala.collection.mutable.ListBuffer 

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

Wenn Sie möchten, können Sie dies mithilfe von .toList in eine Liste konvertieren

Chalith Tharuka
quelle
0

In Ihrem Fall verwende ich: val dm = ListBuffer[String]()undval dk = ListBuffer[Map[String,anyRef]]()

Rom
quelle