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 是不可变对象,所以我想创建并返回新列表。

我编写了以下代码:

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),例如src (length=x) 和dest (length=y>=x)。我想用src列表中的元素替换dest列表的前x 个元素。

4

5 回答 5

8

你的意思是scala.collection.immutable.List?它是不可变的。无需复制它们。不可变意味着没有什么可以改变它,所以你可以在不同的线程中使用它。

在 Scala 中创建集合的通用方法是 builder。你可以从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如下方法:

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

更新

require(src.length <= dest.length, "IndexOutOfBoundsException")
src ++ dest.drop(src.length)
于 2012-12-10T12:52:13.600 回答
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)
于 2012-12-10T12:58:28.423 回答
3

如果您想获得更新的列表,您可以在列表中使用地图。Map 通过将函数应用于列表中的每个元素并返回更新的列表来工作。

http://www.brunton-spall.co.uk/post/2011/12/02/map-map-and-flatmap-in-scala/

于 2012-12-10T13:01:24.583 回答
2

你可以使用:

if(dest.length <= src.length) dest ::: src.drop(dest.length)
else dest.dropRight(dest.length - src.length) //or throw exception...
于 2012-12-10T12:31:02.163 回答
1

也许你想要类似的东西

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

我推广到Seqs,但它List当然适用于 s

如果在运行时未完成,该require方法将抛出IllegalArgumentException

然后您只需y-x要将目标列表的最后一个 ( ) 元素附加到源列表(其中 x = src.length;y = dest.length)

您可以通过从 中删除 x元素dest并将其余元素附加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)
于 2012-12-10T14:00:03.273 回答