Làm thế nào để khai báo danh sách trống và sau đó thêm chuỗi trong scala?


79

Tôi có mã như thế này:

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

.....

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

nhưng nó ném thời gian chạy java.lang.UnsupportedOperationException.

Tôi cần khai báo danh sách trống hoặc bản đồ trống và một số vị trí sau này trong mã cần điền chúng.


Điều gì khiến bạn nghĩ rằng có một addhoạt động trên List?
Debilski

Nếu bạn muốn sử dụng thao tác thêm, bạn sẽ phải khai báo ArrayList. Vals trong scala về cơ bản là bất biến, vì vậy bạn không thể thêm vào chúng.
Phantom73

1
iirc val giống như cuối cùng, bạn có thể thêm chúng nếu bạn sử dụng Bộ sưu tập có thể thay đổi. ví dụ: scala-lang.org/api/current/scala/collection/mutable/…
DaVinci

1
@rjc Bạn đang sử dụng phiên bản scala nào? Của tôi (2.9.0) cho tôi một lỗi biên dịch.
paradigmatic

4
Bạn đã nhập khẩu scala.collection.JavaConversions? Nếu bạn đã làm vậy, bạn đang thấy lý do chính tại sao tôi khuyên bạn nên JavaConvertersthay thế: dmdkđang được chuyển đổi thành một bộ sưu tập Java, và sau đó addphương thức được gọi trên bộ sưu tập đó. Tệ hơn dmdkkhông được sửa đổi, ngay cả khi bạn không gặp lỗi. Và, bằng cách này, lỗi là 1 -> "ok"được Map[Int,String], không phải Map[String, Object].
Daniel C. Sobral

Câu trả lời:


116

Danh sách Scala là bất biến theo mặc định. Bạn không thể "thêm" một phần tử, nhưng bạn có thể tạo một danh sách mới bằng cách thêm phần tử mới vào phía trước. Vì đây là danh sách mới , bạn cần phải gán lại tham chiếu (vì vậy bạn không thể sử dụng val).

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

.....

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

Người điều hành ::tạo danh sách mới. Bạn cũng có thể sử dụng cú pháp ngắn hơn:

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

NB: Trong scala không sử dụng kiểu Objectbut Any, AnyRefhoặc AnyVal.


Câu trả lời rất hay nhưng bạn có thể biết nếu tôi khai báo danh sách như trong câu trả lời của bạn, chúng thuộc loại scala.collections.mutable hay là loại không thay đổi được? REPL đã không làm rõ điều này.
rjc

2
Theo mặc định. Nếu bạn không nhập gì. Listlà bất biến. Đó là khuyến nghị cho hầu hết các sử dụng.
paradigmatic

11
@rjc Scala không có mutable.List- Listlà một kiểu cụ thể, trong đó cách triển khai duy nhất là bất biến. Có các lớp bất biến như LinkedListDoubleLinkedList, hầu hết là các lớp trợ giúp. Scala tương đương với Java ArrayListArrayBuffer, và tương đương với Java LinkedListListBuffer. Đặc điểm tương ứng với Java ListSeq- trong đó có collection.Seqvà, mở rộng nó, collection.immutable.Seqcollection.mutable.Seq.
Daniel C. Sobral

@paradigmatic có sự khác biệt giữa ::=+=?
Mahdi

@Mahdi Có thể có sự khác biệt. Trên danh sách chỉ ::được xác định vì vậy +=sẽ không hoạt động. Trên bộ sưu tập khác (không có trong lib tiêu chuẩn): Nếu ::=hoặc +=được triển khai, việc triển khai sẽ được sử dụng. Nếu không, trình biên dịch sẽ chuyển x::=ythành x = y::xx+=yinro x=x+y. Trong trường hợp thứ hai, họ đều giống nhau nếu việc thực hiện ::cũng giống như việc thực hiện +...
paradigmatic

17

Nếu bạn cần thay đổi nội dung, hãy sử dụng ArrayBufferhoặc LinkedBufferthay thế. Tuy nhiên, sẽ tốt hơn nếu giải quyết tuyên bố này:

Tôi cần khai báo danh sách trống hoặc bản đồ trống và một số nơi sau này trong mã cần điền chúng.

Thay vì làm điều đó, hãy điền vào danh sách bằng mã trả về các phần tử. Có nhiều cách để làm điều đó và tôi sẽ đưa ra một số ví dụ:

// 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

Như mọi người đã đề cập, đây không phải là cách tốt nhất để sử dụng danh sách trong 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

Bạn có thể cho biết nếu danh sách của bạn được khai báo giống như trong câu trả lời của bạn, nó sẽ cho hiệu suất thời gian chạy tốt hơn so với câu trả lời bằng mô hình? Giả sử hàng triệu phần tử sẽ được thêm vào danh sách.
rjc

Nó phụ thuộc vào những gì bạn đang cố gắng đạt được. Tôi khuyên bạn nên bắt đầu với một bất biến như @paradigmatic đã đề xuất. Sự phức tạp của việc thêm một phần tử vào danh sách bất biến như thế này: list ::= "text"O (1) là hằng số và là điều tốt nhất bạn có thể làm.
agilesteel

rjc: khuyết điểm của danh sách bất biến là O (1); tuy nhiên, điều thực sự quan trọng là kiểu truy cập của bạn liên quan đến hiệu quả. Ví dụ: nếu thứ tự quan trọng và bạn phải xây dựng danh sách bằng cách thêm vào, thì Vector là lựa chọn tốt hơn (bất biến).
Kris Nuttycombe

6

Như đã đề cập trong câu trả lời ở trên , Danh sách Scala là một tập hợp bất biến. Bạn có thể tạo một danh sách trống với .empty[A]. Sau đó, bạn có thể sử dụng một phương pháp :+, +:hoặc ::để thêm phần tử vào danh sách.

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))


0

Có thể bạn có thể sử dụng ListBuffers trong scala để tạo danh sách trống và thêm chuỗi sau đó vì ListBuffers có thể thay đổi. Ngoài ra, tất cả các chức năng Danh sách đều có sẵn cho Bộ đệm danh sách trong 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)

nếu bạn muốn, bạn có thể chuyển đổi danh sách này thành một danh sách bằng cách sử dụng .toList


0

Trong trường hợp của bạn, tôi sử dụng: val dm = ListBuffer[String]()val dk = ListBuffer[Map[String,anyRef]]()

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.