Nhận mục trong danh sách trong Scala?


205

Làm thế nào trên thế giới bạn chỉ nhận được một yếu tố tại chỉ mục i từ Danh sách trong scala?

Tôi đã thử get(i), và [i]- không có gì hoạt động. Googling chỉ trả về cách "tìm" một phần tử trong danh sách. Nhưng tôi đã biết chỉ số của các yếu tố!

Đây là mã không biên dịch:

def buildTree(data: List[Data2D]):Node ={
  if(data.length == 1){
      var point:Data2D = data[0]  //Nope - does not work

  }
  return null
}

Nhìn vào danh sách api không giúp được gì, vì mắt tôi chỉ lướt qua.


1
Chà, có vẻ như data.head đã hoạt động ... Nhưng vẫn chỉ mang đến cho tôi yếu tố đầu tiên chứ không phải bất kỳ ai trong danh sách.
Andriy Drozdyuk

Sử dụng các đặc điểm Seq áp dụng (chỉ mục) nếu bạn chắc chắn chỉ mục không nằm ngoài giới hạn. scala-lang.org/api/c Hiện / Từ
Beezer

data.drop (i) .head hoạt động để truy cập phần tử thứ i
Vinay

@Vinay Đó là một hoạt động tốn kém. Vì vậy, người ta nên tránh "thả (i) .head".
Shubham Agrawal

Câu trả lời:


305

Sử dụng dấu ngoặc đơn:

data(2)

Nhưng bạn không thực sự muốn làm điều đó với các danh sách rất thường xuyên, vì các danh sách được liên kết cần có thời gian để duyệt qua. Nếu bạn muốn lập chỉ mục vào một bộ sưu tập, hãy sử dụng Vector(không thay đổi) hoặc ArrayBuffer(có thể thay đổi) hoặc có thể Array(chỉ là một mảng Java, ngoại trừ một lần nữa bạn lập chỉ mục vào nó (i)thay vì [i]).


1
Về cơ bản tôi đang tìm kiếm một cái gì đó giống như ArrayList trong java. Tôi đoán bất biến cũng sẽ tốt thôi.
Andriy Drozdyuk

1
ArrayBufferhoạt động giống như ArrayList. Vectorhoạt động như một bất biến - ArrayListbạn có thể đọc, nhưng bạn không thể viết mà không tạo một cái mới.
Rex Kerr

Làm thế nào về một danh sách con? Ví dụ trong java tôi làm "data.subList (0, index)".
Andriy Drozdyuk

Đừng bận tâm, tôi hiểu rồi - đó là "lát"! Tôi có thể chuyển đổi ArrayBuffer thành Vector không? Hoặc có một loại chung hơn mà tôi có thể trả về từ các phương thức? Ví dụ trong Java tôi sẽ trả về giao diện List.
Andriy Drozdyuk

1
Bạn có thể chuyển đổi ArrayBuffersang IndexedSeqsử dụng .toIndexedSeq; IndexedSeqlà loại chung chung hơn. (Trong trường hợp này, nó thực sự hóa ra là a Vector.) IndexedSeqLà siêu tập hợp các bộ sưu tập hợp lý để lập chỉ mục. Ngoài ra, lưu ý rằng bạn có thể làm Vector() ++ myArrayBuffer, nó sẽ hoạt động cho hầu hết mọi bộ sưu tập (ở hai bên). ++xây dựng một bộ sưu tập mới từ hai bạn chỉ định, giữ nguyên kiểu của cái bên trái. Vector()là vector trống, vì vậy nó sẽ tạo ra những gì bạn muốn.
Rex Kerr

121

An toàn hơn là sử dụng liftđể bạn có thể trích xuất giá trị nếu nó tồn tại và thất bại một cách duyên dáng nếu không.

data.lift(2)

Điều này sẽ trả về Không nếu danh sách không đủ dài để cung cấp phần tử đó và Một số (giá trị) nếu có.

scala> val l = List("a", "b", "c")
scala> l.lift(1)
Some("b")
scala> l.lift(5)
None

Bất cứ khi nào bạn thực hiện một thao tác có thể thất bại theo cách này, thật tuyệt khi sử dụng Tùy chọn và lấy hệ thống loại để đảm bảo bạn đang xử lý trường hợp phần tử không tồn tại.

Giải trình:

Điều này hoạt động bởi vì List apply(mà đường chỉ là dấu ngoặc đơn, ví dụ l(index)) giống như một hàm một phần được xác định bất cứ nơi nào danh sách có một phần tử. Các List.liftphương pháp biến một phần applychức năng (một chức năng mà chỉ được định nghĩa cho một số đầu vào) vào một chức năng bình thường (được định nghĩa cho bất kỳ đầu vào) bởi về cơ bản gói kết quả trong một Option.


11
Nâng là đẹp. Tôi có thể tránh các lỗi ArrayIndexOutOfBound, mà không cần kiểm tra kích thước của mảng ..
Naveen Sachar

9

Tại sao dấu ngoặc đơn?

Dưới đây là trích dẫn từ chương trình sách trong scala .

Một ý tưởng quan trọng khác được minh họa bằng ví dụ này sẽ cho bạn cái nhìn sâu sắc về lý do tại sao các mảng được truy cập bằng dấu ngoặc đơn trong Scala. Scala có ít trường hợp đặc biệt hơn Java. Mảng đơn giản là các thể hiện của các lớp như bất kỳ lớp nào khác trong Scala. Khi bạn áp dụng dấu ngoặc đơn bao quanh một hoặc nhiều giá trị cho một biến, Scala sẽ chuyển đổi mã thành một lời gọi của một phương thức có tên áp dụng trên biến đó. Vì vậy, helloStrings (i) được chuyển đổi thành helloStrings.apply (i). Do đó, việc truy cập một phần tử của một mảng trong Scala chỉ đơn giản là một cuộc gọi phương thức như bất kỳ phần tử nào khác. Nguyên tắc này không bị giới hạn trong các mảng: bất kỳ ứng dụng nào của một đối tượng cho một số đối số trong ngoặc đơn sẽ được chuyển thành một lệnh gọi phương thức áp dụng. Tất nhiên điều này sẽ chỉ biên dịch nếu loại đối tượng đó thực sự định nghĩa một phương thức áp dụng. Vì vậy, nó không phải là một trường hợp đặc biệt; đó là một quy tắc chung.

Dưới đây là một vài ví dụ về cách kéo phần tử nhất định (elem đầu tiên trong trường hợp này) bằng cách sử dụng kiểu lập trình chức năng.

  // Create a multdimension Array 
  scala> val a = Array.ofDim[String](2, 3)
  a: Array[Array[String]] = Array(Array(null, null, null), Array(null, null, null))
  scala> a(0) = Array("1","2","3")
  scala> a(1) = Array("4", "5", "6")
  scala> a
  Array[Array[String]] = Array(Array(1, 2, 3), Array(4, 5, 6))

  // 1. paratheses
  scala> a.map(_(0))
  Array[String] = Array(1, 4)
  // 2. apply
  scala> a.map(_.apply(0))
  Array[String] = Array(1, 4)
  // 3. function literal
  scala> a.map(a => a(0))
  Array[String] = Array(1, 4)
  // 4. lift
  scala> a.map(_.lift(0))
  Array[Option[String]] = Array(Some(1), Some(4))
  // 5. head or last 
  scala> a.map(_.head)
  Array[String] = Array(1, 4)

2

Vui lòng sử dụng dấu ngoặc đơn () để truy cập các phần tử danh sách list_name (index)


0

Đây là cách ưa thích để truy cập dữ liệu của Danh sách thông qua chỉ mục hiện nay:

scala> val list = List("a","b","c")
scala> list.get(1)
Some("b")
scala> list.get(5)
None

Nhưng giống như Rex Kerr đã nói ở trên: Nếu bạn đang sử dụng các chỉ mục, bạn nên xem xét sử dụng Vector thay vì Danh sách.

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.