Obter item da lista em Scala?

205

Como você obtém apenas um elemento no índice i da Lista em scala?

Eu tentei get(i)e [i]- nada funciona. O Google retorna apenas como "encontrar" um elemento na lista. Mas eu já sei o índice do elemento!

Aqui está o código que não compila:

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

  }
  return null
}

Olhar para a lista api não ajuda, pois meus olhos simplesmente se cruzam.

Andriy Drozdyuk
fonte
1
Bem, parece que o data.head funcionou ... Mas ainda assim, isso me dá apenas o primeiro elemento, não nenhum da lista.
Andriy Drozdyuk
Use as características Seq aplicar (índice) se tiver certeza de que o índice não está fora dos limites. scala-lang.org/api/current/…
Beezer
data.drop (i) .head obras para o acesso i-th elemento
Vinay
@ Vinay Essa é uma operação cara. Portanto, deve-se evitar "drop (i) .head".
Shubham Agrawal

Respostas:

305

Use parênteses:

data(2)

Mas você realmente não quer fazer isso com listas com muita frequência, pois as listas vinculadas levam tempo para serem percorridas. Se você deseja indexar em uma coleção, use Vector(imutável) ou ArrayBuffer(mutável) ou possivelmente Array(que é apenas uma matriz Java, mas novamente você indexa nela com em (i)vez de [i]).

Rex Kerr
fonte
1
Basicamente, estou procurando algo como ArrayList em java. Eu acho que imutável seria bom também.
Andriy Drozdyuk
1
ArrayBufferfunciona como ArrayList. Vectorfunciona como um imutável - você ArrayListpode ler, mas não pode escrever sem criar um novo.
Rex Kerr
Que tal uma subLista? Por exemplo, em java, faço "data.subList (0, index)".
Andriy Drozdyuk
Deixa pra lá, eu entendi - é "fatia"! Posso converter ArrayBuffer para Vector? Ou existe um tipo mais genérico que eu possa retornar dos métodos? Por exemplo, em Java, eu retornaria a interface List.
Andriy Drozdyuk
1
Você pode converter ArrayBufferpara um IndexedSequso .toIndexedSeq; IndexedSeqé o tipo mais genérico. (Nesse caso, ele acaba sendo implementado como a Vector.) IndexedSeqÉ o supertipo de coleções razoáveis ​​para indexação. Além disso, observe que você pode fazer isso Vector() ++ myArrayBuffer, o que funcionará em quase todas as coleções (em ambos os lados). ++cria uma nova coleção a partir das duas que você especificar, preservando o tipo da que está à esquerda. Vector()é o vetor vazio, portanto produziria o que você deseja.
Rex Kerr
121

Mais seguro é usar liftpara que você possa extrair o valor, se ele existir, e falhar normalmente, se não existir.

data.lift(2)

Isso retornará None se a lista não for longa o suficiente para fornecer esse elemento e Some (value) se for.

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

Sempre que você estiver executando uma operação que pode falhar dessa maneira, é ótimo usar uma Opção e obter o sistema de tipos para ajudar a garantir que você esteja lidando com o caso em que o elemento não existe.

Explicação:

Isso funciona porque a lista apply(que inclui apenas parênteses, por exemplo l(index)) é como uma função parcial que é definida sempre que a lista tiver um elemento. O List.liftmétodo transforma a applyfunção parcial (uma função que é definida apenas para algumas entradas) em uma função normal (definida para qualquer entrada), envolvendo basicamente o resultado em uma Opção.

adamnfish
fonte
11
O elevador é lindo. Eu posso evitar erros de arrayIndexOutOfBound, sem verificar o tamanho da matriz.
Naveen Sachar
9

Por que parênteses?

Aqui está a citação da programação do livro em scala .

Outra idéia importante ilustrada por este exemplo fornecerá informações sobre por que as matrizes são acessadas com parênteses no Scala. Scala tem menos casos especiais que Java. Matrizes são simplesmente instâncias de classes como qualquer outra classe no Scala. Quando você aplica parênteses em torno de um ou mais valores a uma variável, o Scala transforma o código em uma invocação de um método denominado apply nessa variável. Então greetStrings (i) é transformado em greetStrings.apply (i). Assim, acessar um elemento de uma matriz no Scala é simplesmente uma chamada de método como qualquer outra. Esse princípio não se restringe a matrizes: qualquer aplicação de um objeto a alguns argumentos entre parênteses será transformada em uma chamada de método apply. Obviamente, isso será compilado apenas se esse tipo de objeto realmente definir um método de aplicação. Portanto, não é um caso especial; é uma regra geral.

Aqui estão alguns exemplos de como extrair determinado elemento (primeiro elem neste caso) usando o estilo de programação funcional.

  // 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)
B.Mr.W.
fonte
2

Use parênteses () para acessar os elementos da lista list_name (index)

Deepan Chakravarthi
fonte
0

Esta é a maneira preferida de acessar dados de uma lista via índice hoje em dia:

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

Mas, como Rex Kerr mencionou acima: Se você estiver usando índices, considere usar Vector em vez de uma Lista.

arma de fogo
fonte