创建 Scala 列表的首选方式

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1241166/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 01:34:40  来源:igfitidea点击:

Preferred way to create a Scala list

scala

提问by agilefall

There are several ways to construct an immutable list in Scala (see contrived example code below). You can use a mutable ListBuffer, create a varlist and modify it, use a tail recursivemethod, and probably others that I don't know about.

有几种方法可以在 Scala 中构造不可变列表(请参阅下面的人为示例代码)。您可以使用可变 ListBuffer,创建一个var列表并修改它,使用尾递归方法,以及我不知道的其他方法。

Instinctively, I use the ListBuffer, but I don't have a good reason for doing so. Is there a preferred or idiomatic method for creating a list, or are there situations that are best for one method over another?

我本能地使用 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)
}

采纳答案by Daniel C. Sobral

ListBufferis a mutable list which has constant-time append, and constant-time conversion into a List.

ListBuffer是一个可变列表,它具有恒定时间附加和恒定时间转换为List.

Listis immutable and has constant-time prepend and linear-time append.

List是不可变的,并且具有恒定时间前置和线性时间追加。

How you construct your list depends on the algorithm you'll use the list for and the order in which you get the elements to create it.

您构建列表的方式取决于您将使用该列表的算法以及您获取创建它的元素的顺序。

For instance, if you get the elements in the opposite order of when they are going to be used, then you can just use a Listand do prepends. Whether you'll do so with a tail-recursive function, foldLeft, or something else is not really relevant.

例如,如果您以与将要使用的时间相反的顺序获取元素,那么您可以只使用 aList和 do 前置。您是否会使用尾递归函数foldLeft、 或其他东西来这样做并不真正相关。

If you get the elements in the same order you use them, then a ListBufferis most likely a preferable choice, if performance is critical.

如果您以相同的顺序获取元素,那么 aListBuffer很可能是更好的选择,如果性能至关重要。

But, if you are not on a critical path and the input is low enough, you can always reversethe list later, or just foldRight, or reversethe input, which is linear-time.

但是,如果您不在关键路径上并且输入足够低,那么您总是可以reverse稍后列出,或者只是foldRight,或者reverse输入,这是线性时间。

What you DON'Tdo is use a Listand append to it. This will give you much worse performance than just prepending and reversing at the end.

你什么不要做的是使用一个List,并追加到它。这会给你带来比在最后添加和反转更糟糕的性能。

回答by Daniel C. Sobral

And for simple cases:

对于简单的情况:

val list = List(1,2,3) 

:)

:)

回答by Alexander Azarov

Uhmm.. these seem too complex to me. May I propose

嗯……这些对我来说似乎太复杂了。我可以提议吗

def listTestD = (0 to 3).toList

or

或者

def listTestE = for (i <- (0 to 3).toList) yield i

回答by JasonG

You want to focus on immutability in Scala generally by eliminating any vars. Readability is still important for your fellow man so:

您通常希望通过消除任何变量来关注 Scala 中的不变性。可读性对你的同胞来说仍然很重要,所以:

Try:

尝试:

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)

You probably don't even need to convert to a list in most cases :)

在大多数情况下,您甚至可能不需要转换为列表:)

The indexed seq will have everything you need:

索引序列将拥有您需要的一切:

That is, you can now work on that IndexedSeq:

也就是说,您现在可以处理该 IndexedSeq:

scala> list.foldLeft(0)(_+_)
res0: Int = 55

回答by André Laszlo

Note: This answer is written for an old version of Scala.

注意:此答案是为旧版本的 Scala 编写的。

The Scala collection classes are going to be redesigned as of Scala 2.8, so be prepared to change the way you create lists very soon.

Scala 集合类将在 Scala 2.8 中重新设计,因此准备好尽快改变您创建列表的方式。

What is the forward compatible way of creating a List? I have no idea since I haven't read the 2.8 docs yet.

创建列表的前向兼容方式是什么?我不知道,因为我还没有阅读 2.8 文档。

A PDF document describing the proposed changes of the collection classes

描述集合类的拟议更改的 PDF 文档

回答by Walter Chang

I always prefer List and I use "fold/reduce" before "for comprehension". However, "for comprehension" is preferred if nested "folds" are required. Recursion is the last resort if I can not accomplish the task using "fold/reduce/for".

我总是更喜欢 List 并且我在“理解”之前使用“折叠/减少”。但是,如果需要嵌套的“折叠”,则首选“用于理解”。如果我无法使用“fold/reduce/for”完成任务,递归是最后的手段。

so for your example, I will do:

所以对于你的例子,我会这样做:

((0 to 3) :\ List[Int]())(_ :: _)

before I do:

在我做之前:

(for (x <- 0 to 3) yield x).toList

Note: I use "foldRight(:\)" instead of "foldLeft(/:)" here because of the order of "_"s. For a version that does not throw StackOverflowException, use "foldLeft" instead.

注意:由于“_”的顺序,我在这里使用“foldRight(:\)”而不是“foldLeft(/:)”。对于不抛出 StackOverflowException 的版本,请改用“foldLeft”。

回答by elm

Using List.tabulate, like this,

使用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)

回答by Yuli Reiri

As a new scala developer i wrote small test to check list creation time with suggested methods above. It looks like (for ( p <- ( 0 to x ) ) yield p) toList the fastest approach.

作为一名新的 Scala 开发人员,我编写了一个小测试,以使用上述建议的方法检查列表创建时间。看起来 (for ( p <- ( 0 to x ) ) yield p) toList 是最快的方法。

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")
    }
  }
}

回答by Arne

just an example that uses collection.breakOut

只是一个使用 collection.breakOut 的例子

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)

回答by KayV

To create a list of string, use the following:

要创建字符串列表,请使用以下命令:

val l = List("is", "am", "are", "if")