0

I have a Seq of objects like Seq(x1, x2, x3, x4) and I want to tranform it to Seq(y1, y2, y3, y4)

What is the most efficient way of doing so

Right now I am

val seq1 = Seq(x1, x2, x3......)
var seq2 = Seq[MyType2]()



for (myObj <- seq1) {
    seq2 = seq2 :+ myObj.tranformToType2
}

The problem is that the scala doc says

https://www.scala-lang.org/api/2.12.x/scala/collection/Seq.html

a new sequence consisting of all elements of this sequence followed by elem.

so I was wondering what is the most idiomatic/efficient way of tranforming a list of object to another list of object

user16367669
  • 57
  • 1
  • 8
  • 1
    If you care about performance then don't use `Seq` since it is an interface you can't know the efficiency of any operation. Rather use any concrete collection like `List`, `Vector`, `ArraySeq`, etc. And pick the one that provides you with the complexity constraints that are better suited for your code. – Luis Miguel Mejía Suárez Nov 17 '21 at 12:53

2 Answers2

2

The code you wrote is Scala imperative style, but Scala aims to be a functional language.

The functional approach being:

val seq2 = seq1.map(myObj => myObj.tranformToType2)

// Or shorter:
val seq2 = seq1.map(_.tranformToType2)

map is one of the most useful operation in function programming. You will see that you'll use it everywhere when you need to transform something into something else.

As a rule of thumb, whenever you see a var and a for loop, this is smelly and you should ask yourself how do I do this the functional way?

Gaël J
  • 11,274
  • 4
  • 17
  • 32
  • follow up question , internally, how does map work? does it allocate a new array of the same size as the original array, and append to it? why is the internal append more efficient than :+ – user16367669 Nov 17 '21 at 06:12
  • 2
    `Seq` is not an array, it is an abstract interface to a sequence that may be implemented in a number of different ways (`List`, `Vector`, `View` etc.). It is up to the implementation of the underlying type to work out how best to implement `map`, and the performance will depend on what the underlying type is. – Tim Nov 17 '21 at 06:49
  • so when I init a seq `Seq(x1, x2, x3......)` what is the undelying backing datastructure? is it a linked list or indexed array? – user16367669 Nov 17 '21 at 16:16
  • 1
    By default it's a `List` which is immutable linked list. You might want to have a look to https://stackoverflow.com/questions/10866639/difference-between-a-seq-and-a-list-in-scala/10866807#10866807 and also read the Scaladoc of the different implementations if you believe performance is critical in your use case. – Gaël J Nov 17 '21 at 18:36
  • 1
    Also `map` might not be more efficient than your loop _but_ it's more idiomatic in the sense that you describe what you want to do rather than how to do it. – Gaël J Nov 17 '21 at 18:38
0

map is the function that you are looking for. Check the docs for details.

A simplistic example:

case class MyType1(x: String)
case class MyType2(x: Int)

val ls: Seq[MyType2] = Seq(MyType1("hello"), MyType1("world")).map(mt1 => MyType2(mt1.content.length))
Johny T Koshy
  • 3,857
  • 2
  • 23
  • 40