Dostać przedmiot z listy w Scali?


205

Jak, u licha, dostajesz tylko element o indeksie i z listy w scali?

Próbowałem get(i)i [i]- nic nie działa. Googling zwraca tylko sposób „znalezienia” elementu na liście. Ale znam już indeks elementu!

Oto kod, który się nie kompiluje:

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

  }
  return null
}

Spojrzenie na api List nie pomaga, bo moje oczy po prostu się krzyżują.


1
Cóż, wygląda na to, że data.head zadziałało ... Ale to daje mi tylko pierwszy element, a nie żaden z listy.
Andriy Drozdyuk

Użyj sekw cechy zastosowania (indeks) , jeśli jesteś pewien, że indeks nie jest poza granicami. scala-lang.org/api/current/…
Beezer

data.drop (i) .head działa dla uzyskania dostępu do i-tego elementu
Vinay

@Vinay To kosztowna operacja. Dlatego należy unikać „drop (i) .head”.
Shubham Agrawal

Odpowiedzi:


305

Użyj nawiasów:

data(2)

Ale tak naprawdę nie chcesz tego często robić z listami, ponieważ listy połączone wymagają czasu przejścia. Jeśli chcesz zaindeksować kolekcję, użyj Vector(niezmiennej) lub ArrayBuffer(mutowalnej) lub ewentualnie Array(która jest tylko tablicą Java, z tym wyjątkiem, że ponownie indeksujesz w niej (i)zamiast zamiast [i]).


1
Zasadniczo szukam czegoś takiego jak ArrayList w Javie. Myślę, że niezmienne też byłoby w porządku.
Andriy Drozdyuk

1
ArrayBufferdziała jak ArrayList. Vectordziała jak niezmienny ArrayList- możesz czytać, ale nie możesz pisać bez tworzenia nowego.
Rex Kerr,

Co powiesz na listę podrzędną? Na przykład w java robię „data.subList (0, index)”.
Andriy Drozdyuk

Nieważne, mam to - to „kawałek”! Czy mogę przekonwertować ArrayBuffer na Vector? A może istnieje bardziej ogólny typ, który mogę zwrócić z metod? Na przykład w Javie zwróciłbym interfejs listy.
Andriy Drozdyuk

1
Możesz przekonwertować ArrayBufferna IndexedSequsing .toIndexedSeq; IndexedSeqjest bardziej ogólnym typem. (W tym przypadku okazuje się, że jest zaimplementowane jako a Vector.) IndexedSeqJest nadtypem kolekcji, do których uzasadnione jest indeksowanie. Pamiętaj też, że możesz to zrobić Vector() ++ myArrayBuffer, co będzie działać dla prawie każdej kolekcji (po obu stronach). ++buduje nową kolekcję z dwóch określonych przez ciebie, zachowując typ z lewej. Vector()jest pustym wektorem, więc wytworzy to, co chcesz.
Rex Kerr,

121

Bezpieczniej jest używać, liftaby można było wyodrębnić wartość, jeśli istnieje, i z wdziękiem, jeśli nie istnieje.

data.lift(2)

Zwróci Brak, jeśli lista nie jest wystarczająco długa, aby zapewnić ten element, a Niektóre (wartość), jeśli tak jest.

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

Za każdym razem, gdy wykonujesz operację, która może się nie powieść, dobrze jest użyć Opcji i uzyskać system typów, aby upewnić się, że zajmujesz się przypadkiem, w którym element nie istnieje.

Wyjaśnienie:

Działa to, ponieważ List apply(który cukry to tylko nawiasy, np. l(index)) Jest jak funkcja częściowa, która jest definiowana wszędzie tam, gdzie lista ma element. List.liftSposób przekształca częściowo applyfunkcję (funkcji, który jest zdefiniowany jedynie przez kilka wejść) do normalnego funkcjonowania (zdefiniowaną dla każdego wejścia) o zasadniczo owijania wynik w opcję.


11
Winda jest piękna. Mogę uniknąć błędów arrayIndexOutOfBound, bez sprawdzania rozmiaru tablicy ..
Naveen Sachar

9

Dlaczego nawiasy?

Oto cytat z programowania książek w scali .

Inna ważna idea zilustrowana tym przykładem daje wgląd w to, dlaczego tablice są dostępne w nawiasach w Scali. Scala ma mniej specjalnych przypadków niż Java. Tablice są po prostu instancjami klas, jak każda inna klasa w Scali. Kiedy zastosujesz nawiasy otaczające jedną lub więcej wartości do zmiennej, Scala przekształci kod w wywołanie metody o nazwie zastosuj do tej zmiennej. Tak więc greetStrings (i) przekształca się w greetStrings.apply (i). W ten sposób dostęp do elementu tablicy w Scali jest po prostu wywołaniem metody, jak każde inne. Ta zasada nie ogranicza się do tablic: każde zastosowanie obiektu do niektórych argumentów w nawiasach zostanie przekształcone w wywołanie metody zastosuj. Oczywiście skompiluje się to tylko wtedy, gdy ten typ obiektu faktycznie zdefiniuje metodę zastosuj. To nie jest szczególny przypadek; to ogólna zasada.

Oto kilka przykładów, jak wyciągnąć określony element (w tym przypadku pierwszy element) za pomocą funkcjonalnego stylu programowania.

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


0

Jest to obecnie preferowany sposób dostępu do danych Listy za pośrednictwem indeksu:

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

Ale tak jak Rex Kerr wspomniany powyżej: Jeśli używasz indeksów, powinieneś rozważyć użycie Vector zamiast Listy.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.