Reputation: 1089
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.
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.
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.
Upvotes: 2
Views: 367
Reputation: 22595
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))
}
}
Upvotes: 3
Reputation: 27356
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)
}
Upvotes: 3
Reputation: 4063
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!
Upvotes: 3