Thomas
Thomas

Reputation: 8958

foreach() in scala returns a Seq. How to get to the item?

I'm trying to add every element of a list to a MutableSet.

Thrift:

Obj {
  list<Tag> myList;
}

enum Tag {
  ...
}

Scala:

val uniqueTags = Set[Tag]()
// obj is of type Obj defined in the thrift above
obj.flatMap(_.myList).foreach(uniqueTags += _)

However the compiler says that I'm trying to add Seq[Tag] instead of Tag. How to get to the element represented by Seq?

Also I'm sure there is another way to initialize the Set with the list directly. I tried obj.flatMap(_.myList).toSet() and Set[Tag](obj.flatMap(_.myList))) but none worked.

Upvotes: 1

Views: 1382

Answers (2)

prayagupadhyay
prayagupadhyay

Reputation: 31232

you don't need to iterate to find unique, scala does that for you with toSet

Example using toSet:

scala> case class Obj(myList: List[String])
defined class Obj

scala> val obj = Option(Obj(myList = List("metal", "rock", "prog", "pop", "pop")))
obj: Option[Obj] = Some(Obj(List(metal, rock, prog, pop, pop)))

Now, to get unique tags,

scala> val uniqueTags = obj.map(_.myList).getOrElse(List.empty[String]).toSet
uniqueTags: scala.collection.immutable.Set[String] = Set(metal, rock, prog, pop)

foreach are not recommended to mutate stuffs in fp world. The other approach would be to use accumulator pattern - foldLeft,

scala> import scala.collection.immutable.Set
import scala.collection.immutable.Set

scala> obj.map(_.myList).getOrElse(List.empty[String]).foldLeft(Set[String]()){ case (s, e) => s + e }
res15: scala.collection.immutable.Set[String] = Set(metal, rock, prog, pop)

The mutable approach is to use forach as you are doing, (not recommended)

scala> val uniqueTags = scala.collection.mutable.Set[String]()
uniqueTags: scala.collection.mutable.Set[String] = HashSet()

scala> obj.map(_.myList).getOrElse(List.empty[String]).foreach { elem => uniqueTags += elem }

scala> uniqueTags
res13: scala.collection.mutable.Set[String] = HashSet(metal, rock, pop, prog)

Upvotes: 3

tomcy
tomcy

Reputation: 455

I an not sure what is Obj. But in you case: obj.flatMap(_.myList) will give a list of Tag. I think the correct way is:

obj.flatMap(_.myList).foreach(uniqueTags += _)

I think you can use mutable in Scala. Its not a big deal. According to your obj, you may use different way to append the element into set

case class Obj(myList: List[String])
val obj = Obj(List("1", "2", "3"))

// first example when your obj is a single Obj
val uniqueTags = mutable.Set[String]()
// obj is of type Obj defined in the thrift above
obj.myList.foreach(uniqueTags += _)
printf(uniqueTags.toString()) // give you Set(1, 2, 3)

// second example when your obj is a list of Obj
val obj2 = List(obj, obj, obj)
val uniqueTags2 = mutable.Set[String]()
obj2.flatMap(_.myList).foreach(uniqueTags2 += _)
printf(uniqueTags2.toString()) // give you Set(1, 2, 3) also

Upvotes: 0

Related Questions