2012-12-10 54 views
4

我想在Scala中創建通用(不變)方法,將元素從源列表複製到目標列表。在Java中有副本方法java.util.Collections(請參閱http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Collections.html#copy%28java.util.List,%20java.util.List%29)。我知道在Scala List中是不可變的對象,所以我想創建並返回新的列表。將元素從一個列表複製到Scala中的另一個

我已經寫了下面的代碼:

def copy[T](dest:List[T], src:List[T]):List[T] = { 
    if(dest.length<src.length) throw new Exception("IndexOutOfBoundsException") 
    else if(src==Nil) dest 
    else { 
     var ret = dest 
     ret = dest.updated(0, src.first) 
     var i=1 
     val f:(T=>Unit) = a => { 
      if(i<src.length) ret=ret.updated(i, src(i)) 
      i+=1 
      () 
     } 
     dest.foreach(f) 
     ret 
    } 
} 

但我認爲它可以寫更好。你能幫我寫更好的代碼嗎?提前致謝。

編輯:也許我表達不清楚我想做什麼。我有兩個列表(scala.collection.immutable.List),例如(長度= x)和dest(長度= y> = x)。我想先替換x元素dest列表中元素來自src列表。

+3

得到什麼意思'scala.collection.immutable.List'?它是不可變的。無需複製它們。 – senia

+0

根據你的編輯:你想在原地做? (例如,如果會有第三個列表,說明由於這樣的替換導致「更新」,你會不高興嗎?) –

+0

這將是最好的做法。我有解決方案,但如果存在更好的解決方案,我很樂意看到它。 – Paul

回答

1

你可以使用:

if(dest.length <= src.length) dest ::: src.drop(dest.length) 
else dest.dropRight(dest.length - src.length) //or throw exception... 
+0

謝謝,這也是一個好主意。 – Paul

8

你的意思是scala.collection.immutable.List?它是不可變的。無需複製它們。不可變意味着什麼都不能改變它,所以你可以在不同的線程中使用它。

在scala中創建集合的一般方法是構建器。您可以從CanBuildFrom對象中獲得一個。或者,您可以從genericBuilder收集實例的方法中獲取它。

scala> val list = List(1, 2, 3) 
list: List[Int] = List(1, 2, 3) 

scala> val b = list.genericBuilder[Int] 
b: scala.collection.mutable.Builder[Int,List[Int]] = ListBuffer() 

scala> list.foreach{ b += _ } 

scala> val result = b.result // this code is useless. `val result = list` is enough 
result: List[Int] = List(1, 2, 3) 

如果你想創建一個基於現有的收集不同類型的新的集合,你可以使用collection.breakOut methid這樣的:

scala> val list = List('a', 'b', 'c') 
list: List[Char] = List(a, b, c) 

scala> val result: String = list.map{identity}(collection.breakOut) 
result: String = abc 

UPD

require(src.length <= dest.length, "IndexOutOfBoundsException") 
srC++ dest.drop(src.length) 
+1

有關BreakOut和CanBuildFrom的更多詳細信息[請參閱此文章](http://stackoverflow.com/a/1716558/298389) –

+0

謝謝,很高興知道這一點。但我想要做其他事情。也許我解釋得不太好,我在我的問題上添加了一些東西。 – Paul

+1

@Paul:我已經更新了我的答案。 – senia

3

你所想程序上太過分了,說出你想要的不是怎麼做......

怎麼樣:

val src = List(1,2,3) 
val dest = src map {x => x} 

,如果你真的想它

def copy[T](src: List[T]): List[T] = src map {x => x} 

功能響應OP的更新:(這也提出了其他人)

def copy[T](src: List[T], dest: List[T]): List[T] = srC++ dest.drop(src.length) 
+0

也謝謝。但我想要做其他事情。也許我解釋得不太好,我在我的問題上添加了一些東西。 – Paul

1

也許你想要的東西,像

def copy[T](dest: Seq[T], src: Seq[T]): Seq[T] = { 
    require(dest.length >= src.length) 
    srC++ (dest drop src.length) 
} 

我概括爲Seq S,但它適用於List S,當然

require方法拋出IllegalArgumentException如果在運行時不會實現

然後你只需要一個將目標列表的最後一個(y-x)元素添加到源列表(其中x = src.length; Y = dest.length)

您可以通過做到這一點從dest下降x元素附加剩下的由src

這是你從REPL

scala> val src = List(1, 2, 3, 4) 
src: List[Int] = List(1, 2, 3, 4) 

scala> val dst = List(10, 20) 
dst: List[Int] = List(10, 20) 

scala> val dst2 = List(10, 20, 30, 40, 50, 60) 
dst2: List[Int] = List(10, 20, 30, 40, 50, 60) 

scala> copy(dst, src) 
java.lang.IllegalArgumentException: requirement failed 
     at scala.Predef$.require(Predef.scala:221) 
     at .copy(<console>:8) 
     at .<init>(<console>:11) 
     at .<clinit>(<console>) 
     at .<init>(<console>:7) 
     at .<clinit>(<console>) 
     <...> 

scala> copy(dst2, src) 
res1: Seq[Int] = List(1, 2, 3, 4, 50, 60) 
+0

也謝謝你,很好的解決方案。 – Paul

+0

@senia在她的更新中提出了同樣的解決方案......她的回答在主要答案中陷入了僵局,我一開始並沒有看到這一點。 –

相關問題