Какой лучший способ создать динамически растущий массив в Scala?
Я хотел динамически добавлять элементы в массив. Но кажется, что Scala массивы и списки не предоставляют никаких методов для динамического добавления элементов из-за непреложной природы.
Поэтому я решил использовать тип данных List, чтобы использовать этот метод :: для достижения этого. Мой код выглядит следующим образом
var outList = List(Nil)
val strArray = Array("ram","sam","bam")
for (str<-strArray)
outList = str :: outList
Хотя это работает в некотором роде, проблема в том, что новые строки предварительно добавлены в список. Но идеальным требованием является порядок данных. Да, я знаю, что вы думаете, вы можете отменить окончательный список результатов, чтобы получить первоначальный заказ. Но проблема в том, что это огромный массив. И я считаю, что это не решение, хотя оно решает проблему. Я считаю, что должен быть простой способ решить эту проблему...
И моей причиной взлома Scala является изучение функционального способа кодирования. Имея var (изменяемый тип) и заполняя список "на лету", кажется мне не функциональным способом решения вещей.
Как я могу это сделать?
В идеале я хочу достичь чего-то подобного в Scala (ниже С#)
List<int> ls = new List<int>();
for (int i = 0; i < 100; i++)
ls.Add(i);
Ответы
Ответ 1
Но кажется, что Scala Массивы и списки не предоставляют никаких методов для динамического добавления элементов из-за непреложного характера.
Ну, нет. Scala Массивы - это просто массивы Java, поэтому они изменяемы:
val arr = Array(1,2)
arr(0) = 3 // arr == Array(3, 2)
Но так же, как массивы Java (и C/С++/С#/etc.), вы не можете изменить размер массива.
Итак, вам нужна еще одна коллекция, которая поддерживается массивом, но позволяет изменять размер. Подходящей коллекцией в Scala является scala.collection.mutable.ArrayBuffer
, java.util.ArrayList
на Java и т.д.
Если вы хотите получить List
вместо Array
в конце, используйте scala.collection.mutable.ListBuffer
.
Ответ 2
Если вы хотите использовать изменяемый буфер, как упоминалось выше. Это выглядит так:
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)
Ответ 3
Если вы хотите работать с неизменяемыми структурами, вы можете использовать метод ++:
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)
Если вам нужна производительность при работе со списками, лучше отменить результат, чем пытаться добавить новые элементы в конце. Добавление элементов в конец в список неудобно: -)
Ответ 4
Хорошо, есть несколько вещей, которые нужно прояснить.
Это неправильно, вы делаете один список элементов, содержащий пустой список:
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
.
Ответ 5
Следуя за ответным ответом:
Если вы все еще хотите использовать список, есть несколько способов добавить элемент в список. Что вы можете сделать (да, верхняя часть все еще не так):
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 не весело?;)
P.S. Возможно, причиной, почему вы хотите сделать их неизменными, является скорость. Обработка больших данных будет более эффективной с неизменяемыми типами данных. Я прав?
Ответ 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 в обоих вышеприведенных примерах, поэтому вам может потребоваться вызвать метод toList на нем, если вам нужны некоторые из методов List.
Ответ 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(","))