Cách sao chép hoặc sao chép danh sách trong kotlin


102

Làm thế nào để sao chép danh sách trong Kotlin?

Tôi đang sử dụng

val selectedSeries = mutableListOf<String>()
selectedSeries.addAll(series)

Có cách nào dễ dàng hơn không?


1
Tôi nghĩ giải pháp của bạn đã là cách dễ nhất, trong trường hợp bạn không cần nhân bản sâu.
Serdar Samancıoğlu

Câu trả lời:


144

Điều này hoạt động tốt.

val selectedSeries = series.toMutableList()

6
val selectedSeries = series.toList()cũng hoạt động vì nó gọi toMutableList()trong quá trình thực hiện của nó.
Flávio Faria

4
@ FlávioFaria chỉ thử nghiệm nó với ===và phải nói toList()không sao chép các bộ sưu tập, nhưng toMutableList()không
Peppermint Paddy

3
@PeppermintPaddy Nó không sao chép, ngoại trừ trong trường hợp danh sách rỗng. Nếu nguồn trống, Iterable.toList()trả về emptyList(), luôn trả về cùng một đối tượng (không thay đổi). Vì vậy, nếu bạn kiểm tra với emptyList()bạn, bạn sẽ nhận lại được cùng một đối tượng.
Laurence Gonsalves

52
Cá nhân tôi không thích ý tưởng này ... Không có gì trong tài liệu cấp toMutableList()sẽ trả về một phiên bản mới của danh sách nếu phiên bản gọi phương thức đã là một danh sách có thể thay đổi.
BrunoJCM

4
đây không phải là một câu trả lời hay và chắc chắn không phải là một câu trả lời đúng, không có gì đảm bảo rằng việc triển khai trong tương lai có thể thay đổi, trừ khi được ghi lại cụ thể rằng cuộc gọi phương thức này sẽ luôn trả về một bản sao mới.
Bhargav

23

Bạn có thể dùng

Danh sách -> toList ()

Mảng -> toArray ()

ArrayList -> toArray ()

MutableList -> toMutableList ()


Thí dụ:

val array = arrayListOf("1", "2", "3", "4")

val arrayCopy = array.toArray() // copy array to other array

Log.i("---> array " ,  array?.count().toString())
Log.i("---> arrayCopy " ,  arrayCopy?.count().toString())

array.removeAt(0) // remove first item in array 

Log.i("---> array after remove" ,  array?.count().toString())
Log.i("---> arrayCopy after remove" ,  arrayCopy?.count().toString())

in nhật ký:

array: 4
arrayCopy: 4
array after remove: 3
arrayCopy after remove: 4

14

Tôi có thể nghĩ ra hai cách thay thế:

1. val selectedSeries = mutableListOf<String>().apply { addAll(series) }

2. val selectedSeries = mutableListOf(*series.toTypedArray())

Cập nhật: với công cụ Suy luận kiểu mới (chọn tham gia trong Kotlin 1.3), Chúng tôi có thể bỏ qua tham số kiểu chung trong ví dụ đầu tiên và có điều này:

1. val selectedSeries = mutableListOf().apply { addAll(series) }

FYI: Cách chọn tham gia Suy luận mới là kotlinc -Xnew-inference ./SourceCode.ktcho dòng lệnh hoặc kotlin { experimental { newInference 'enable'}cho Gradle. Để biết thêm thông tin về Suy luận kiểu mới, hãy xem video này: KotlinConf 2018 - Suy luận kiểu mới và các tính năng ngôn ngữ liên quan của Svetlana Isakova , đặc biệt là 'suy luận cho người xây dựng' ở tuổi 30 '


nên được tách thành 2 câu trả lời imho, vì tôi nghĩ câu đầu tiên là đúng, nhưng cái sau thiếu một số đẹp.
Holger Brandl

@Jacob Wu: Tôi rất ngạc nhiên khi thấy biểu tượng * trong giải pháp thứ hai không tạo ra lỗi. Nó làm gì? Tôi đã thực hiện tìm kiếm với "phép nhân một bậc" nhưng không tìm thấy gì.
Lensflare

1
@Lensflare * phương tiện để hủy một mảng thành các mục riêng biệt, ví dụ như mutableListOf (* [1, 2, 3]) có nghĩa là mutableListOf (1, 2, 3), nó giống như các hoạt động đối diện với vararg
Jacob Wu

1
@Jacob Wu: Cảm ơn bạn. Với câu trả lời của bạn, tôi đã có thể phát hiện ra rằng toán tử được gọi là "toán tử spread". Tôi thấy nó hữu ích như thế nào bằng cách kết hợp một số tham số với một mảng vào danh sách varargs. Nhưng nó có lợi ích gì trong ví dụ của bạn? Nó nhanh hơn hay sao? Hay nó là chìa khóa để đảm bảo rằng bộ sưu tập được sao chép?
Lensflare

@Lensflare Tôi nghĩ lợi ích chỉ là cú pháp - mã ngắn và không cần loại chung rõ ràng (như trong ví dụ đầu tiên của tôi). Đằng sau cảnh, tôi tin rằng mã được biên dịch cho các hoạt động mảng, vì vậy hiệu suất phải giống nhau.
Jacob Wu


9

Bạn có thể sử dụng tiện ích mở rộng Iterable.toMutableList()được cung cấp sẽ cung cấp cho bạn một danh sách mới. Thật không may, như chữ ký và tài liệu của nó gợi ý, nó có nghĩa là để đảm bảo rằng an Iterablelà một List(giống như toStringvà nhiều to<type>phương pháp khác ). Không có gì đảm bảo với bạn rằng nó sẽ là một danh sách mới . Ví dụ: thêm dòng sau vào đầu tiện ích mở rộng: if (this is List) return thislà một cải tiến hiệu suất hợp pháp (nếu nó thực sự cải thiện hiệu suất).

Ngoài ra, vì tên của nó, mã kết quả không rõ ràng lắm.

Tôi muốn thêm tiện ích mở rộng của riêng mình để chắc chắn về kết quả và tạo mã rõ ràng hơn nhiều (giống như chúng ta có đối với mảng ):

fun <T> List<T>.copyOf(): List<T> {
    val original = this
    return mutableListOf<T>().apply { addAll(original) }
}

fun <T> List<T>.mutableCopyOf(): MutableList<T> {
    val original = this
    return mutableListOf<T>().apply { addAll(original) }
}

Lưu ý rằng đó addAlllà cách nhanh nhất để sao chép vì nó sử dụng bản gốc System.arraycopytrong việc triển khai ArrayList.

Ngoài ra, hãy cẩn thận rằng điều này sẽ chỉ cung cấp cho bạn một bản sao nông .


Tôi thích giải pháp này. Không nên addAll(this@copyOf), vì thisbên trong applysẽ tham chiếu đến danh sách trống mới tạo? Hoặc là hoặc mutableListOf<T>().also { it.addAll(this) }?
Franko Leon Tokalić

5

Đối với một bản sao cạn, tôi đề nghị

.map{it}

Điều đó sẽ hoạt động đối với nhiều loại bộ sưu tập.


1
Lưu ý rằng nó không hoạt động đối với Maps. Nó biên dịch, nhưng vì itlà một Map.Entry, và bản sao là nông, bạn có các mục giống nhau.
noamtm

1
@noamtm vâng, đó là những gì tôi muốn nói với bản sao cạn. Phương pháp này sẽ không bao giờ sao chép các mục nhập. Nó sẽ chỉ tạo một bản sao của bộ sưu tập với các mục giống nhau. Bản đồ không có gì đặc biệt ở đây.
Lensflare

2
Quan điểm của tôi là, mặc dù nó cũng hấp dẫn để sử dụng nó trên bản đồ, và nó biên dịch và có vẻ hoạt động - nó không thực sự hoạt động.
noamtm 10/09/19

4

Cũng giống như trong Java:

Danh sách:

    val list = mutableListOf("a", "b", "c")
    val list2 = ArrayList(list)

Bản đồ:

    val map = mutableMapOf("a" to 1, "b" to 2, "c" to 3)
    val map2 = HashMap(map)

Giả sử bạn đang nhắm mục tiêu JVM (hoặc Android); Tôi không chắc nó hoạt động với các mục tiêu khác, vì nó dựa trên các hàm tạo bản sao của ArrayList và HashMap.


2

Tôi sẽ sử dụng các toCollection()phương pháp khuyến nông :

val original = listOf("A", "B", "C")
val copy = original.toCollection(mutableListOf())

Thao tác này sẽ tạo mới MutableListvà sau đó thêm từng phần tử của bản gốc vào danh sách mới được tạo.

Kiểu suy luận ở đây sẽ là MutableList<String>. Nếu bạn không muốn tiết lộ khả năng thay đổi của danh sách mới này, bạn có thể khai báo kiểu rõ ràng dưới dạng danh sách bất biến:

val copy: List<String> = original.toCollection(mutableListOf())

0

Đối với danh sách đơn giản có nhiều giải pháp bên trên.

Tuy nhiên, nó chỉ dành cho danh sách nông.

Hàm dưới đây hoạt động cho 2 chiều bất kỳ ArrayList. ArrayListtrong thực tế, tương đương với MutableList. Điều thú vị là nó không hoạt động khi sử dụng MutableListkiểu rõ ràng . Nếu một người cần nhiều kích thước hơn, thì cần tạo nhiều chức năng hơn.

fun <T>cloneMatrix(v:ArrayList<ArrayList<T>>):ArrayList<ArrayList<T>>{
  var MatrResult = ArrayList<ArrayList<T>>()
  for (i in v.indices) MatrResult.add(v[i].clone() as ArrayList<T>)
  return MatrResult
}

Demo cho Ma trận số nguyên:

var mat = arrayListOf(arrayListOf<Int>(1,2),arrayListOf<Int>(3,12))
var mat2 = ArrayList<ArrayList<Int>>()
mat2 = cloneMatrix<Int>(mat)
mat2[1][1]=5
println(mat[1][1])

nó cho thấy 12



-1

Hãy thử mã dưới đây để sao chép danh sách trong Kotlin

arrayList2.addAll(arrayList1.filterNotNull())
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.