Ricevi elementi nell'elenco in Scala?


205

Come diavolo ottieni solo un elemento all'indice i dall'elenco in scala?

Ho provato get(i)e [i]- niente funziona. Googling restituisce solo come "trovare" un elemento nell'elenco. Ma conosco già l'indice dell'elemento!

Ecco il codice che non viene compilato:

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

  }
  return null
}

Guardare la lista API non aiuta, poiché i miei occhi si incrociano.


1
Bene, sembra che data.head abbia funzionato ... Ma questo mi dà solo il primo elemento, non uno nella lista.
Andriy Drozdyuk,

Usa i tratti Seq si applicano (indice) se sei sicuro che l'indice non sia fuori limite. scala-lang.org/api/current/…
Beezer il

data.drop (i) .head funziona per accedere all'i-esimo elemento
Vinay

@Vinay Questa è un'operazione costosa. Quindi si dovrebbe evitare "drop (i) .head".
Shubham Agrawal,

Risposte:


306

Usa le parentesi:

data(2)

Ma non vuoi davvero farlo con le liste molto spesso, poiché le liste collegate richiedono tempo per attraversare. Se si desidera indicizzare in una raccolta, utilizzare Vector(immutabile) o ArrayBuffer(mutabile) o eventualmente Array(che è solo un array Java, tranne per il fatto che si indicizza in esso con (i)invece di [i]).


1
Fondamentalmente sto cercando qualcosa come ArrayList in Java. Immagino che anche l'immutabile andrebbe bene.
Andriy Drozdyuk,

1
ArrayBufferfunziona come ArrayList. Vectorfunziona come un immutabile: ArrayListpuoi leggere, ma non puoi scrivere senza crearne uno nuovo.
Rex Kerr,

Che ne dici di un elenco secondario? Ad esempio in Java faccio "data.subList (0, indice)".
Andriy Drozdyuk,

Non importa, l'ho capito - è "fetta"! Posso convertire ArrayBuffer in Vector? Oppure esiste un tipo più generico che posso restituire dai metodi? Ad esempio in Java vorrei restituire l'interfaccia Elenco.
Andriy Drozdyuk,

1
È possibile convertire ArrayBufferin un IndexedSequtilizzo .toIndexedSeq; IndexedSeqè il tipo più generico. (In questo caso risulta essere implementato come a Vector.) IndexedSeqÈ il supertipo di raccolte in cui è ragionevole indicizzare. Inoltre, tieni presente che potresti farlo Vector() ++ myArrayBuffer, che funzionerà per quasi tutte le raccolte (su entrambi i lati). ++crea una nuova raccolta dalle due specificate, preservando il tipo di quella a sinistra. Vector()è il vettore vuoto, quindi produrrebbe ciò che vuoi.
Rex Kerr,

121

È più sicuro usare liftcosì puoi estrarre il valore se esiste e fallire con grazia se non lo fa.

data.lift(2)

Ciò restituirà None se l'elenco non è abbastanza lungo da fornire quell'elemento e Some (valore) se lo è.

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

Ogni volta che si esegue un'operazione che potrebbe non riuscire in questo modo, è bello usare un'opzione e ottenere il sistema di tipi per assicurarsi di gestire il caso in cui l'elemento non esiste.

Spiegazione:

Questo funziona perché List's apply(che zuccherà solo tra parentesi, ad esempio l(index)) è come una funzione parziale che viene definita ovunque l'elenco abbia un elemento. Il List.liftmetodo trasforma la applyfunzione parziale (una funzione definita solo per alcuni input) in una funzione normale (definita per qualsiasi input) avvolgendo sostanzialmente il risultato in un'opzione.


11
L'ascensore è bellissimo. Posso evitare errori arrayIndexOutOfBound, senza controllare le dimensioni dell'array ..
Naveen Sachar

9

Perché le parentesi?

Ecco la citazione dal libro di programmazione in scala .

Un'altra idea importante illustrata da questo esempio ti darà un'idea del perché si accede alle matrici con le parentesi in Scala. Scala ha meno casi speciali di Java. Le matrici sono semplicemente istanze di classi come qualsiasi altra classe in Scala. Quando si applicano parentesi che racchiudono uno o più valori a una variabile, Scala trasformerà il codice in un richiamo di un metodo chiamato applica su quella variabile. Quindi greetStrings (i) viene trasformato in greetStrings.apply (i). Quindi accedere a un elemento di un array in Scala è semplicemente una chiamata di metodo come qualsiasi altra. Questo principio non è limitato alle matrici: qualsiasi applicazione di un oggetto ad alcuni argomenti tra parentesi verrà trasformata in una chiamata di metodo apply. Naturalmente questo verrà compilato solo se quel tipo di oggetto definisce effettivamente un metodo di applicazione. Quindi non è un caso speciale; è una regola generale.

Ecco alcuni esempi su come estrarre determinati elementi (primo elemento in questo caso) usando lo stile di programmazione funzionale.

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


-1

Questo è il modo preferito per accedere ai dati di un elenco tramite indice al giorno d'oggi:

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

Ma come Rex Kerr menzionato sopra: se stai usando gli indici, dovresti considerare di usare Vector invece di un Elenco.


value get non è un membro di List [String]
Greenev
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.