【问题标题】:What's the best way to create a dynamically growing array in Scala?在 Scala 中创建动态增长数组的最佳方法是什么?
【发布时间】:2011-03-23 02:02:17
【问题描述】:

我想将项目动态添加到数组中。但似乎 Scala 数组和列表由于不可变的特性而没有提供任何动态添加项目的方法。

所以我决定使用 List 数据类型来利用这个 :: 方法来实现这一点。我的代码是这样的

var outList = List(Nil)
val strArray = Array("ram","sam","bam")

for (str<-strArray)
     outList = str :: outList

虽然它以某种方式工作,但问题是新字符串预先附加到列表中。但理想的要求是数据的顺序。是的,我知道你在想什么,你可以把最终的结果列表倒过来得到原来的顺序。但问题是它是一个巨大的数组。我相信这不是一个解决方案,尽管它解决了问题。我相信应该有一个简单的方法来解决这个问题......

而我破解 Scala 的原因是学习函数式编码方式。在我看来,拥有 var (可变类型)并动态填充列表并不是解决问题的实用方法。

我该怎么做?

理想情况下,我想在 Scala 中实现类似的功能(在 C# 代码下方)

List<int> ls = new List<int>();    
for (int i = 0; i < 100; i++)
    ls.Add(i);

【问题讨论】:

    标签: scala


    【解决方案1】:

    但似乎 Scala 数组和列表由于不可变的性质而没有提供任何动态添加项目的方法。

    嗯,不。 Scala 数组只是 Java 数组,所以它们可变的:

    val arr = Array(1,2)
    
    arr(0) = 3 // arr == Array(3, 2)
    

    但就像 Java(和 C/C++/C#/等)数组一样,您无法更改数组的大小

    所以你需要另一个集合,它由一个数组支持,但允许调整大小。 Scala 中合适的集合是scala.collection.mutable.ArrayBuffer、Java 中的java.util.ArrayList 等。

    如果你想最后得到List 而不是Array,请改用scala.collection.mutable.ListBuffer

    【讨论】:

      【解决方案2】:

      追寻回溯的答案:

      如果您仍想使用列表,有几种方法可以将项目添加到列表中。您可以做的是(是的,顶部仍然是错误的):

      scala> var outList : List[String] = Nil
      outList: List[String] = List()
      
      scala> val strArray = Array("a","b","c")
      strArray: Array[java.lang.String] = Array(a, b, c)
      
      scala> for(s <- strArray)      
           | outList = outList :+ s
      
      scala> outList
      res2: List[String] = List(a, b, c)
      

      注意 :+ 运算符。如果你更愿意追加,你会使用 s +: outList。

      现在谁说在 Scala 中编程不好玩? ;)

      附:也许你想让它们不可变的原因是速度。使用不可变数据类型处理大数据会更有效。我说的对吗?

      【讨论】:

      • 请注意,for(s &lt;- strArray) { outList = outList :+ s } 需要二次时间。
      • 啊,混蛋!真的吗? outList ::: s 呢?您对 scala 函数的复杂性有任何参考吗?我尝试谷歌搜索没有找到任何东西。来自stackoverflow.com/questions/1241166/… 我认为普遍的共识是前置和反转。
      • 相同。 List 是一个不可变的链表,因此将 1 个元素附加到一个元素上——无论你使用什么方法——必须花费线性时间(因为你必须复制它的所有元素),所以这个循环需要二次时间。追加到ListBuffer 并调用toList 比前置和反转要好,但是前置和反转比追加到List 要好得多
      【解决方案3】:

      如果你想使用一个可变的缓冲区,就像提到的反义词。它看起来像这样:

      scala> var outList = scala.collection.mutable.Buffer[String]()
      outList: scala.collection.mutable.Buffer[String] = ArrayBuffer()
      
      scala> for(str<-strArray) outList += str                          
      
      scala> outList
      res10: scala.collection.mutable.ListBuffer[String] = ListBuffer(ram, sam, bam)
      

      不管怎样,或许直接用strArray做你想做的事情会更好。例如:

      strArray map(_.toUpperCase) foreach(println)
      

      【讨论】:

        【解决方案4】:

        如果要使用不可变结构,可以使用 ++ 方法:

        scala> val orgList = List(1,2,3)
        orgList: List[Int] = List(1, 2, 3)
        
        scala> val list2Add = List(4,5,6)
        list2Add: List[Int] = List(4, 5, 6)
        
        scala> val newList = orgList ++ list2Add
        newList: List[Int] = List(1, 2, 3, 4, 5, 6)
        

        如果你想对元素做更多的工作而不是仅仅添加它们,你可以使用高阶函数:

        val newList = orgList ++ list2Add.map(_ * 2)
        newList: List[Int] = List(1, 2, 3, 8, 10, 12)
        

        或者使用 for 循环:

        val newList = orgList ++ {for(x <- list2Add) yield 2*x}
        

        或者你可以创建一些递归循环:

        def addAll(toList: List[Int], fromList: List[Int]): List[Int] =
          fromList match {
            case x :: tail => addAll(2*x :: toList, tail)
            case Nil => toList
          }
        
        val newList = addAll(orgList, list2Add )
        

        但在这种情况下,添加元素的顺序将颠倒:

        List(12, 10, 8, 1, 2, 3)
        

        如果您希望在使用列表时获得性能,最好将结果反转而不是尝试在最后添加新元素。最后将元素添加到列表中并不好:-)

        【讨论】:

        • 这不是要求...我想动态填充列表“。大小未知。它可以是基于传入数据的任何内容..我已经更新了我的问题以更清楚
        【解决方案5】:

        好的,有几件事需要澄清。

        这是错误的,你正在创建一个单元素列表,其中包含一个空列表:

        scala> var outList = List(Nil) 
        outList: List[object Nil] = List(List())
        

        Nil 是空列表:

        scala> var outList: List[String] = Nil
        outList: List[String] = List()
        

        或者,如果您愿意:

        scala> var outList = List[String]() 
        outList: List[String] = List()
        

        没有更多上下文,很难知道“动态”是什么意思。您的示例代码最好写成:

        scala> val strArray = Array("ram","sam","bam")
        strArray: Array[java.lang.String] = Array(ram, sam, bam)
        
        scala> strArray toList
        res0: List[java.lang.String] = List(ram, sam, bam)
        

        如果您想要一个可以增长并有效处理前置、追加和插入操作的可变集合,您可以使用scala.mutable.Buffer

        【讨论】:

        • 在“我想动态填充列表”的意义上动态。尺寸未知。它可以是任何基于传入数据的东西。我已经更新了我的问题以更清楚
        【解决方案6】:

        如果你想创建一个新的集合,你可以使用 yield 关键字:

        val outlist = for(i <- 0 to 100) yield i
        

        或者:

        val arrList = "Some" :: "Input" :: "List" :: Nil
        val outlist = for ( i <- arrList ) yield i
        

        从技术上讲,outlist 在上述两个示例中都是一个 Seq,因此如果您需要 List 的某些方法,则可能需要对其调用 toList 方法。

        【讨论】:

        • 你甚至不需要说for(i &lt;- 0 to 100) yield i。您可以只说 (0 to 100),如果需要,可以使用 .toList 方法或类似方法将其转换为不同的集合。
        【解决方案7】:

        我们可以按照建议使用 ArrayBuffer。 但是,我创建了一个简单的程序,它不接受 int 数组的参数,它可以让您输入数字,最后我们将显示它们。

        val arraySize = scala.io.StdIn.readLine().toInt
          val arr = new ArrayBuffer[Int]() ++ (1 to arraySize).map{
            i =>
              scala.io.StdIn.readLine().toInt
          }
          println(arr.mkString(","))
        

        【讨论】:

          猜你喜欢
          • 2022-08-04
          • 1970-01-01
          • 2021-01-24
          • 1970-01-01
          • 1970-01-01
          • 2013-01-12
          • 2021-09-09
          • 2013-03-26
          • 1970-01-01
          相关资源
          最近更新 更多