0

I have a List[MyObject], with MyObject containing the fields field1, field2 and field3.

I'm looking for an efficient way of doing :

Tuple3(_.map(_.field1), _.map(_.field2), _.map(_.field3))

In java I would do something like :

Field1Type f1 = new ArrayList<Field1Type>();
Field2Type f2 = new ArrayList<Field2Type>();
Field3Type f3 = new ArrayList<Field3Type>();


for(MyObject mo : myObjects) {
    f1.add(mo.getField1());
    f2.add(mo.getField2());
    f3.add(mo.getField3());
}

I would like something more functional since I'm in scala but I can't put my finger on it.

2 Answers 2

3

Get 2\3 sub-groups with unzip\unzip3

Assuming the starting point:

val objects: Seq[MyObject] = ???

You can unzip to get all 3 sub-groups:

val (firsts, seconds, thirds) =  
  objects
    .unzip3((o: MyObject) => (o.f1, o.f2, o.f3))

What if I have more than 3 relevant sub-groups ?

If you really need more sub-groups you need to implement your own unzipN however instead of working with Tuple22 I would personally use an adapter:


case class MyObjectsProjection(private val objs: Seq[MyObject]) {
  
  lazy val f1s: Seq[String] =
    objs.map(_.f1)

  lazy val f2s: Seq[String] =
    objs.map(_.f2)

    ... 
  
  lazy val f22s: Seq[String] =
    objs.map(_.f3)
}

val objects: Seq[MyClass] = ???
val objsProjection = MyObjectsProjection(objects)

objs.f1s
objs.f2s
...
objs.f22s

Notes:

  • Change MyObjectsProjection according to your needs.
  • This is from a Scala 2.12\2.11 vanilla perspective.
Sign up to request clarification or add additional context in comments.

4 Comments

For scala 3 users: you can leverage generic tuple: elements.map(Tuple.fromProductTyped(_)).unzip3
What if I have more than 3 fields later ?
Even if MyClass has more fields you can select just 2\3 relevant fields with unzip\unzip3. You need to add your own implementations for bigger tuples or just rethink your algorithm. TBH instead of working with Tuple20 i would make a case class adapter.
I updated the post with a generic adapter as well
2

The following will decompose your objects into three lists:

case class MyObject[T,S,R](f1: T, f2: S, f3: R)

val myObjects: Seq[MyObject[Int, Double, String]] = ???

val (l1, l2, l3) = myObjects.foldLeft((List.empty[Int], List.empty[Double], List.empty[String]))((acc, nxt) => {
  (nxt.f1 :: acc._1, nxt.f2 :: acc._2, nxt.f3 :: acc._3)
})

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.