2010-07-30 3 views
29

Ich wollte Elemente dynamisch in ein Array hinzufügen. Scala Arrays und Listen bieten jedoch keine Methoden zum dynamischen Hinzufügen von Objekten aufgrund der unveränderlichen Natur.Was ist der beste Weg, um ein dynamisch wachsendes Array in Scala zu erstellen?

Also entschied ich mich, den Datentyp List zu verwenden, um diese :: Methode zu verwenden, um dies zu erreichen. Mein Code sieht wie folgt aus

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

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

Obwohl es in irgendeiner Art und Weise funktioniert, ist das Problem die neuen Saiten vorgehängten in der Liste. Aber die ideale Anforderung ist die Reihenfolge der Daten. Ja, ich weiß, was du denkst, du kannst die Endergebnisliste umkehren, um die ursprüngliche Reihenfolge zu erhalten. Aber das Problem ist, es ist eine riesige Reihe. Und ich glaube, es ist keine Lösung, obwohl es das Problem löst. Ich glaube, es sollte einen einfachen Weg geben, um dies zu lösen ...

Und mein Grund für das Hacken von Scala ist es, die funktionale Art der Codierung zu lernen. var (veränderlicher Typ) zu haben und die Liste im laufenden Betrieb zu füllen, scheint mir keine funktionale Lösung zu sein.

Wie kann ich es tun?

Idealerweise möchte ich in Scala, so etwas erreichen (unter dem C# Code)

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

Antwort

29

Aber es scheint Scala Arrays & Listen bietet keine Methoden zum dynamischen Hinzufügen von Elementen aufgrund der unveränderlichen Natur.

Nun, nein. Scala Arrays sind nur Java-Arrays, so dass sie sind wandelbar:

val arr = Array(1,2) 

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

Aber wie Java (und C/C++/C#/etc.) Arrays können Sie nicht die Größe eines Arrays ändern .

Sie brauchen also eine andere Sammlung, die von einem Array unterstützt wird, aber Größenänderung erlaubt. Eine geeignete Sammlung in Scala ist scala.collection.mutable.ArrayBuffer, java.util.ArrayList in Java usw.

Wenn Sie einen List anstelle eines Array am Ende erhalten möchten, verwenden scala.collection.mutable.ListBuffer statt.

+4

danke .. "ListBuffer" ist die, die ich wollte .. :) – RameshVel

3

Okay, es gibt ein paar Dinge zu klären.

Das ist falsch, du bist ein ein Element Liste machen, eine leere Liste enthält:

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

Nil ist die leere Liste:

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

Oder, wenn Sie bevorzugen:

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

Ohne mehr Zusammenhang, es ist schwer zu wissen, was Sie mit "dynamisch" meinen. Ihr Beispiel-Code wäre besser geschrieben werden als:

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) 

Wenn Sie eine veränderbare Sammlung möchten, die wachsen und effizient prepend behandeln, hängen und einfügen Operationen, könnten Sie scala.mutable.Buffer verwenden.

+1

fügen Sie bitte Formatierung zu den 2 Beispielen in der Mitte hinzu. –

+0

dynamisch im Sinne "ich möchte die Liste im laufenden Betrieb füllen". Die Größe ist unbekannt. Es könnte alles basierend auf den eingehenden Daten sein ..Ich habe meine Frage für mehr Klarheit aktualisiert – RameshVel

3

Gehen nach retronym Antwort:

Wenn Sie noch Liste verwenden wollen, gibt es ein paar Möglichkeiten, um ein Element der Liste vorangestellt wird. Was Sie tun können, ist (ja der obere Teil ist immer noch falsch):

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) 

Beachten Sie: + Operator. Wenn Sie eher anhängen, würden Sie s +: outList verwenden.

Wer sagt jetzt, Programmierung in Scala macht keinen Spaß? ;)

P.S. Vielleicht ist der Grund, warum Sie sie unveränderlich machen wollen, die Geschwindigkeit. Die Verarbeitung großer Datenmengen ist bei unveränderlichen Datentypen effizienter. Habe ich recht?

+0

Beachten Sie, dass 'für (s <- strArray) {outList = outList: + s}' quadratische Zeit dauert. –

+0

Ahh, bugger! "Ja wirklich?" Was ist mit OutList ::: s? Haben Sie einen Bezug zur Komplexität von Scala-Funktionen? Ich habe versucht zu googeln hat nichts gefunden. Von http://StackOverflow.com/Questions/1241166/preferred-way-to-create-a-Scala-list Ich denke, der allgemeine Konsens besteht darin, vor- und umzukehren. –

+1

Gleiches. 'List' ist eine unveränderbare verkettete Liste, also hängt 1 Element an eins an - welche Methode Sie auch verwenden - _hat lineare Zeit nehmen (da Sie alle seine Elemente kopieren müssen), so dass diese Schleife quadratische Zeit benötigt. Das Anhängen an 'ListBuffer' und das Aufrufen von' toList' ist besser als das Voranstellen und Umkehren, aber das Voranstellen und Umkehren ist _much_ besser als das Anhängen an eine 'Liste'. –

4

Wenn Sie einen veränderbaren Puffer verwenden möchten, wie retronym erwähnt. Es sieht wie folgt aus:

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) 

Wie auch immer, vielleicht ist es besser, direkt auf die Dinge, die Sie mit dem strArray tun wollen. ZB:

strArray map(_.toUpperCase) foreach(println) 
4

Wenn Sie mit unveränderlichen Strukturen arbeiten möchten, können Sie die ++ Methode verwenden:

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) 

Wenn Sie mehr Arbeit an den Elementen zu tun, als sie gerade hinzufügen, die Sie verwenden können Funktionen höherer Ordnung:

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

oder mit einer for-Schleife:

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

Oder Sie könnten eine rekursive Schleife erstellen:

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) 

aber die Reihenfolge der hinzugefügten Elemente in diesem Fall wird in umgekehrt sein:

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

Wenn Sie Leistung wünschen, wenn das Arbeiten mit Listen, ist es Besser, das Ergebnis umzukehren, als am Ende neue Elemente hinzuzufügen. Hinzufügen von Elementen am Ende einer Liste ist nooot gut :-)

+0

das ist nicht Voraussetzung ... ich möchte die Liste im laufenden Betrieb zu füllen. "Die Größe ist unbekannt. Es könnte alles basierend auf den eingehenden Daten sein .. Ich habe meine Frage für mehr Klarheit aktualisiert – RameshVel

2

Wenn Sie eine neue Kollektion zu schaffen suchen, können Sie die Ausbeute Schlüsselwort verwenden:

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

Oder:

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

Technisch ist Outlist ein Seq in den beiden obigen Beispielen, also müssen Sie möglicherweise die toList-Methode darauf aufrufen, wenn Sie einige der Methoden von List benötigen.

+1

Sie müssen nicht einmal sagen "für (i <- 0 bis 100) y". Sie können einfach sagen "(0 bis 100)" und, falls gewünscht, konvertieren Sie es in eine andere Sammlung mit der '.toList' Methode oder so. –

Verwandte Themen