2

I have a case class like this:

case class Metric(name: String, value: Double, timeStamp: Int) 

I receive individual components to build metrics in separate lists and zip them to create a list of Metric objects.

def buildMetric(names: Seq[String], values: Seq[Double], ts: Seq[Int]): Seq[Metric] = { (names, values, ts).zipped.toList map { case (name, value, time) => Metric(name, value, time) } } 

Now I need to add an optional parameter to both buildMetric function and Metric class.

case class Metric(name: String, value: Double, timeStamp: Int, type: Option[Type]) 

&

def buildMetric(names: Seq[String], values: Seq[Double], ts: Seq[Int], types: Option[Seq[Type]]): Seq[Metric] 

The idea is that we some times receive a sequence of the type which if present matches the length of names and values lists. I am not sure how to modify the body of buildMetric function to create the Metric objects with type information idiomatically. I can think of a couple of approaches.

  1. Do an if-else on types.isDefined and then zip the types with types.get with another list in one condition and leave as above in the other. This makes me write the same code twice.

  2. The other option is to simply use a while loop and create a Metric object with types.map(_(i)) passed a last parameter.

So far I am using the second option, but I wonder if there is a more functional way of handling this problem.

3 Answers 3

3

The first option can't be done because zipped only works with tuples of 3 or fewer elements. The second version might look like this:

def buildMetric(names: Seq[String], values: Seq[Double], ts: Seq[Int], types: Option[Seq[Type]]): Seq[Metric] = for { (name, i) <- names.zipWithIndex value <- values.lift(i) time <- ts.lift(i) optType = types.flatMap(_.lift(i)) } yield { Metric(name, value, time, optType) } 
Sign up to request clarification or add additional context in comments.

Comments

3

One more option from my point of view, if you would like to keep this zipped approach - convert types from Option[Seq[Type]] to Seq[Option[Type]] with same length as names filled with None values in case if types is None as well:

val optionTypes: Seq[Option[Type]] = types.fold(Seq.fill(names.length)(None: Option[Type]))(_.map(Some(_))) // Sorry, Did not find `zipped` for Tuple4 case names.zip(values).zip(ts).zip(optionTypes).toList.map { case (((name, value), time), optionType) => Metric(name, value, time, optionType) } 

Hope this helps!

1 Comment

Thanks, I tried this. Its a good approach but I was surprised to see that the Seq.fill operation seem very cpu intensive. When testing this out, cpu utilization in my cluster went up from 4-5 % to 50-70% !
3

You could just use pattern matching on types:

def buildMetric(names: Seq[String], values: Seq[Double], ts: Seq[Int], types: Option[Seq[Type]]): Seq[Metric] = { types match { case Some(types) => names.zip(values).zip(ts).zip(types).map { case (((name, value), ts,), t) => Metric(name, value, ts, Some(t)) } case None => (names, values, ts).zipped.map(Metric(_, _, _, None)) } } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.