Reputation: 2618
I need to duplicate every element in a list. Here is what I came up with for that:
List.range(1,5).map(i => List(i,i)).flatten
which outputs
List[Int] = List(1, 1, 2, 2, 3, 3, 4, 4)
I wonder whether this is the most efficient way to do that (ultimately it needs to run on a lot of data), given that for every element, a new list would be created.
(the above is on an int range, to keep the example simple)
Any suggestions?
Upvotes: 10
Views: 11281
Reputation: 1134
why not
var a = List("a","b","c")
val c = a ::: a
println(c)
Upvotes: 1
Reputation: 3599
Another solution:
Parameter times means how many times do you want repeat each element in the list
def repeatElementsInList[T](list: List[T],times: Int): List[T] = {
list.flatMap (x =>
List.fill(times)(x)
)
}
scala> repeatElementInList(List("a",1,"b"),3)
res6: List[Any] = List(a, a, a, 1, 1, 1, b, b, b)
Upvotes: 4
Reputation: 41749
And yet another version
def dupe[T](xs:List[T]):List[T] =
xs.foldRight(List[T]()) {(elem, acc) => elem::elem::acc}
Probably about as efficient as the map, but saves an extra iteration over the list for the flatten
Upvotes: 2
Reputation: 11366
Do you really need lists? can you do better by being more generic? Lists are often over-used when other collections can be much better suited. Here's a method which takes any Seq and creates a Stream which duplicates the items, Streams are naturally lazy, You won't necessarily have the memory overhead of creating and throwing away a lot of little lists:
def dupe[A](as: Seq[A]): Stream[A] = as match {
case Seq(h, t @ _*) => h #:: h #:: dupe(t)
case _ => Stream.empty
}
We can see that it acts lazily:
scala> dupe(List(1,2,3,4))
res1: Stream[Int] = Stream(1, ?)
Lazily enough that it works in very large or even infinite input:
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)
if you really want a list:
scala> dupe(List(1,2,3,4)).toList
res5: List[Int] = List(1, 1, 2, 2, 3, 3, 4, 4)
Upvotes: 6
Reputation: 20415
Following comments above, for any given methods such as f1(x: Int): Int
and f2(x: Int): Int
, consider
(1 to 5).par.filter { x => f1(x) > f2(x) }
where par
casts the range onto a parallel collection, worth considering for large collections.
Upvotes: 0
Reputation: 55569
A more general solution would be something like:
def duplicate[T](list: List[T]): List[T] = list.flatMap(x => List[T](x, x))
Using immutable collections won't be all that efficient for very large data sets. A simple implementation using the mutable ListBuffer
is already 10 times faster than the above (using a list with one million elements):
def duplicate[T](list: List[T]): List[T] = {
val buffer = collection.mutable.ListBuffer[T]()
list.foreach{ x =>
buffer += x
buffer += x
}
buffer.toList
}
This uses a general technique of appending to a ListBuffer
for performance, then converting to the immutable List
at the end.
Upvotes: 7