Получить элемент в списке в Scala?


205

Как в мире вы получаете элемент по индексу i из списка в Scala?

Я пытался get(i), и [i]- ничего не работает. Поиск в Google возвращает только то, как «найти» элемент в списке. Но я уже знаю индекс элемента!

Вот код, который не компилируется:

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

  }
  return null
}

Глядя на список api не помогает, так как мои глаза просто пересекаются.


1
Ну, похоже, data.head сработал ... Но все же это дает мне только первый элемент, а не кого-то в списке.
Андрей Дроздюк

Используйте черты Seq apply (index), если вы уверены, что индекс не выходит за пределы. scala-lang.org/api/current/…
Бизер

data.drop (i) .head работает для доступа к i-му элементу
Vinay

@ Vinay Это дорогостоящая операция. Поэтому следует избегать «drop (i) .head».
Шубхам Агравал

Ответы:


306

Используйте скобки:

data(2)

Но вы действительно не хотите делать это со списками очень часто, так как связанные списки требуют времени для прохождения. Если вы хотите проиндексировать коллекцию, используйте Vector(неизменяемый) или ArrayBuffer(изменяемый) или, возможно, Array(который является просто массивом Java, за исключением того, что вы снова индексируете его (i)вместо [i]).


1
В основном я ищу что-то вроде ArrayList в Java. Я думаю, что неизменный тоже будет хорошо.
Андрей Дроздюк

1
ArrayBufferработает как ArrayList. Vectorработает как неизменный - ArrayListвы можете читать, но вы не можете написать без создания нового.
Рекс Керр

Как насчет подсписка? Например, в Java я делаю "data.subList (0, index)".
Андрей Дроздюк

Неважно, я понял - это "кусочек"! Могу ли я конвертировать ArrayBuffer в вектор? Или есть более общий тип, который я могу вернуть из методов? Например, в Java я бы вернул интерфейс List.
Андрей Дроздюк

1
Вы можете конвертировать ArrayBufferв IndexedSeqиспользование .toIndexedSeq; IndexedSeqэто более общий тип. (В этом случае фактически оказывается, что он реализован как Vector.) IndexedSeq- это супертип коллекций, в которые целесообразно индексировать. Кроме того, обратите внимание, что вы можете сделать Vector() ++ myArrayBuffer, что будет работать практически для любой коллекции (с обеих сторон). ++строит новую коллекцию из двух указанных вами, сохраняя тип слева. Vector()это пустой вектор, поэтому он будет производить то, что вы хотите.
Рекс Керр,

121

Безопаснее использовать, liftчтобы вы могли извлечь значение, если оно существует, и изящно потерпеть неудачу, если его нет.

data.lift(2)

Это вернет None, если список недостаточно длинный, чтобы предоставить этот элемент, и Some (значение), если это так.

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

Всякий раз, когда вы выполняете операцию, которая может потерпеть неудачу таким образом, замечательно использовать Option и получить систему типов, которая поможет убедиться, что вы обрабатываете случай, когда элемент не существует.

Объяснение:

Это работает, потому что List apply(который, например, l(index)содержит только круглые скобки ) похож на частичную функцию, которая определяется везде, где в списке есть элемент. List.liftСпособ включает частичную applyфункцию (функцию , которая определена только для некоторых входов) в нормальную функцию (определенную для любого входного сигнала) по существу оберточного результата в качестве опции.


11
Лифт прекрасен. Я могу избежать ошибок arrayIndexOutOfBound, не проверяя размер массива ..
Naveen Sachar

9

Почему круглые скобки?

Вот цитата из книги по программированию в Scala .

Другая важная идея, проиллюстрированная этим примером, даст вам понимание того, почему массивы доступны в скобках в Scala. В Scala меньше особых случаев, чем в Java. Массивы - это просто экземпляры классов, как и любой другой класс в Scala. Когда вы применяете круглые скобки, окружающие одно или несколько значений, к переменной, Scala преобразует код в вызов метода с именем apply для этой переменной. Таким образом, greetStrings (i) преобразуется в greetStrings.apply (i). Таким образом, доступ к элементу массива в Scala - это просто вызов метода, как и любой другой. Этот принцип не ограничивается массивами: любое применение объекта к некоторым аргументам в скобках будет преобразовано в вызов метода apply. Конечно, это скомпилируется, только если этот тип объекта действительно определяет метод apply. Так что это не особый случай; это общее правило.

Вот несколько примеров, как вытащить определенный элемент (в данном случае первый элемент), используя стиль функционального программирования.

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

Это предпочтительный способ доступа к данным списка через индекс в настоящее время:

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

Но, как упоминал выше Рекс Керр: если вы используете индексы, вам следует рассмотреть возможность использования Vector вместо List.


значение get не является членом List [String]
Greenev
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.