Як оголосити порожній список, а потім додати рядок у масштабі?


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

Якщо ви хочете скористатися операцією додавання, вам доведеться оголосити ArrayList. Vals в шкалі по суті незмінні, тому ви не можете до них додавати.
Phantom73

1
iirc val більше схожий на final, ви можете додати до них, якщо використовуєте мінливі колекції. наприклад, scala-lang.org/api/current/scala/collection/mutable/…
DaVinci

1
@rjc Яку версію Scala ви використовуєте? Mine (2.9.0) видає мені помилку компіляції.
парадигматичний

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 не використовуйте тип, Objectале Any, AnyRefабо AnyVal.


Дуже хороша відповідь, але чи можете ви сказати, чи оголошую я список, як у вашій відповіді, це тип scala.collections.mutable чи незмінний? REPL не пояснив цього.
rjc

2
За замовчуванням. Якщо нічого не імпортувати. Listє незмінним. Це рекомендований для більшості використання.
парадигматичний

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

@paradigmatic чи є різниця між ::=і +=?
Махді,

@Mahdi Може бути різниця. ::Визначено лише у списках , тому +=не буде працювати. На іншій колекції (не в стандартній бібліотеці): Якщо ::=або +=впроваджено, буде використана реалізація. В іншому випадку, компілятор перетвориться x::=yв x = y::xі x+=yінро x=x+y. У другому випадку вони однакові, якщо реалізація ::така ж, як реалізація +...
парадигматична

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

rjc: мінуси незмінних списків - O (1); однак, насправді важливим є ваш шаблон доступу, що стосується ефективності. Наприклад, якщо порядок має значення, і ви повинні скласти список, додавши його, Vector - кращий (незмінний) вибір.
Kris Nuttycombe

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 у масштабі, щоб створити порожній список і додати рядки пізніше, оскільки ListBuffers можна змінювати. Також усі функції List доступні для ListBuffers у масштабі.

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.