Предпочтительный способ создания списка Scala
существует несколько способов построить неизменяемый список в Scala (см. надуманный пример кода ниже). Вы можете использовать изменяемый ListBuffer, создать var список и изменить его, используйте хвост рекурсивной метод, и, вероятно, другие, о которых я не знаю.
инстинктивно, я использую ListBuffer, но у меня нет веской причины для этого. Есть ли предпочтительный или идиоматический метод для создания списка, или есть ситуации, которые лучше всего подходят для одного метода еще один?
import scala.collection.mutable.ListBuffer
// THESE are all the same as: 0 to 3 toList.
def listTestA() ={
var list:List[Int] = Nil
for(i <- 0 to 3)
list = list ::: List(i)
list
}
def listTestB() ={
val list = new ListBuffer[Int]()
for (i <- 0 to 3)
list += i
list.toList
}
def listTestC() ={
def _add(l:List[Int], i:Int):List[Int] = i match {
case 3 => l ::: List(3)
case _ => _add(l ::: List(i), i +1)
}
_add(Nil, 0)
}
9 ответов:
ListBuffer- Это изменяемый список, который имеет постоянное время добавления и преобразование постоянного времени вList.
Listявляется неизменяемым и имеет постоянное время добавления и линейное время добавления.Способ построения списка зависит от алгоритма, для которого вы будете использовать список, и порядка, в котором вы получаете элементы для его создания.
например, если вы получаете элементы в обратном порядке, когда они будут использоваться, тогда вы можете просто используйте
Listи не добавляет. Если вы будете делать это с помощью хвостовой рекурсивной функции,foldLeft, или что-то еще не очень актуальна.если вы получаете элементы в том же порядке, в котором вы их используете, то a
ListBufferЭто, скорее всего, предпочтительный выбор, если производительность имеет решающее значение.но, если вы не находитесь на критическом пути и вход достаточно низкий, вы всегда можете
reverseСписок позже, или простоfoldRightилиreverseвход, который линейное время.что ты НЕ do-это использование
Listи добавить к нему. Это даст вам гораздо худшую производительность, чем просто добавление и обращение в конце.
Ухмм.. они кажутся мне слишком сложными. Могу я предложить
def listTestD = (0 to 3).toListили
def listTestE = for (i <- (0 to 3).toList) yield i
вы хотите сосредоточиться на неизменности в Scala, как правило, устраняя любые vars. Читаемость по-прежнему важна для вашего собрата так:
попробуй:
scala> val list = for(i <- 1 to 10) yield i list: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)вам, вероятно, даже не нужно конвертировать в список в большинстве случаев :)
индексированный seq будет иметь все, что вам нужно:
то есть теперь вы можете работать над этим IndexedSeq:
scala> list.foldLeft(0)(_+_) res0: Int = 55
Я всегда предпочитаю список, и я использую "сложить/уменьшить" перед "Для понимания". Однако" для понимания "предпочтительнее, если требуются вложенные" складки". Рекурсия-это последнее средство, если я не могу выполнить задачу, используя "fold/reduce/for".
Так что для вашего примера, я буду делать:
((0 to 3) :\ List[Int]())(_ :: _)прежде чем я это сделаю:
(for (x <- 0 to 3) yield x).toListПримечание: я использую "foldRight (:\)" вместо" foldLeft (/:) " здесь из-за порядка "_"s. для версии, которая не бросает StackOverflowException, вместо этого используйте "foldLeft".
используя
List.tabulateвот так,List.tabulate(3)( x => 2*x ) res: List(0, 2, 4) List.tabulate(3)( _ => Math.random ) res: List(0.935455779102479, 0.6004888906328091, 0.3425278797788426) List.tabulate(3)( _ => (Math.random*10).toInt ) res: List(8, 0, 7)
Примечание: этот ответ написан для старой версии Scala.
классы коллекции Scala будут переработаны с версии Scala 2.8, поэтому будьте готовы изменить способ создания списков очень скоро.
каков прямой совместимый способ создания списка? Я понятия не имею, так как я еще не читал документы 2.8.
документ PDF, описывающий предлагаемые изменения классов коллекций
Как новый разработчик scala я написал небольшой тест, чтобы проверить время создания списка с предложенными выше методами. Похоже, что (для ( p
import java.util.Date object Listbm { final val listSize = 1048576 final val iterationCounts = 5 def getCurrentTime: BigInt = (new Date) getTime def createList[T] ( f : Int => T )( size : Int ): T = f ( size ) // returns function time execution def experiment[T] ( f : Int => T ) ( iterations: Int ) ( size :Int ) : Int = { val start_time = getCurrentTime for ( p <- 0 to iterations ) createList ( f ) ( size ) return (getCurrentTime - start_time) toInt } def printResult ( f: => Int ) : Unit = println ( "execution time " + f ) def main( args : Array[String] ) { args(0) match { case "for" => printResult ( experiment ( x => (for ( p <- ( 0 to x ) ) yield p) toList ) ( iterationCounts ) ( listSize ) ) case "range" => printResult ( experiment ( x => ( 0 to x ) toList ) ( iterationCounts ) ( listSize ) ) case "::" => printResult ( experiment ( x => ((0 to x) :\ List[Int]())(_ :: _) ) ( iterationCounts ) ( listSize ) ) case _ => println ( "please use: for, range or ::\n") } } }
просто пример, который использует коллекции.прорыв
scala> val a : List[Int] = (for( x <- 1 to 10 ) yield x * 3)(collection.breakOut) a: List[Int] = List(3, 6, 9, 12, 15, 18, 21, 24, 27, 30) scala> val b : List[Int] = (1 to 10).map(_ * 3)(collection.breakOut) b: List[Int] = List(3, 6, 9, 12, 15, 18, 21, 24, 27, 30)
Comments