标量重复列表中的元素

ben*_*oth 6 scala list-comprehension

我需要复制列表中的每个元素。这是我为此想到的:

List.range(1,5).map(i => List(i,i)).flatten
Run Code Online (Sandbox Code Playgroud)

哪个输出

List[Int] = List(1, 1, 2, 2, 3, 3, 4, 4)
Run Code Online (Sandbox Code Playgroud)

我想知道这是否是最有效的方法(最终它需要在大量数据上运行),因为对于每个元素,都会创建一个新列表。

(上面是一个int范围,为使示例简单起见)

有什么建议么?

Mic*_*jac 6

更通用的解决方案是:

def duplicate[T](list: List[T]): List[T] = list.flatMap(x => List[T](x, x))
Run Code Online (Sandbox Code Playgroud)

对于非常大的数据集,使用不可变集合不会那么有效。使用 mutable 的简单实现ListBuffer已经比上述方法快 10 倍(使用具有一百万个元素的列表):

def duplicate[T](list: List[T]): List[T] = {

    val buffer = collection.mutable.ListBuffer[T]()

    list.foreach{ x =>
        buffer += x
        buffer += x
    }

    buffer.toList
}
Run Code Online (Sandbox Code Playgroud)

这使用附加到ListBuffer性能的通用技术,然后List在最后转换为不可变的。


ste*_*tew 5

您真的需要清单吗?通过更通用可以做得更好?当其他集合更适合时,列表通常会被过度使用。这是一个采用任何Seq并创建重复项的Stream的方法,Streams自然是懒惰的,您不一定会浪费创建和丢弃许多小列表的内存开销:

def dupe[A](as: Seq[A]): Stream[A] = as match { 
  case Seq(h, t @ _*) => h #:: h #:: dupe(t)
  case _ => Stream.empty 
}
Run Code Online (Sandbox Code Playgroud)

我们可以看到它的行为很懒惰:

scala> dupe(List(1,2,3,4))
res1: Stream[Int] = Stream(1, ?)
Run Code Online (Sandbox Code Playgroud)

足够懒惰,它可以在非常大甚至无限的输入中工作:

scala> dupe(Stream.range(1, Int.MaxValue)).take(10).force
res2: scala.collection.immutable.Stream[Int] = Stream(1, 1, 2, 2, 3, 3, 4, 4, 5, 5)

scala> dupe(Stream.continually(1)).take(10).force
res3: scala.collection.immutable.Stream[Int] = Stream(1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
Run Code Online (Sandbox Code Playgroud)

如果您真的想要一个列表:

scala> dupe(List(1,2,3,4)).toList
res5: List[Int] = List(1, 1, 2, 2, 3, 3, 4, 4)
Run Code Online (Sandbox Code Playgroud)