问题
Working with JodaTime, trying to convert a List[LocalDate] to Tuple2[JodaTime, JodaTime] so I can do multi-assigment like so:
val(expire, now) =
List(row.expireDate, new JodaDate) zip (_.toDateTimeAtStartOfDay.getMillis)
which of course does not compile. Is there a similarly concise way to do the above? I know I can just do it manually:
val(expire, now) =
(row.expireDate.toDateTimeAtStartOfDay.getMillis,
new JodaDate().toDateTimeAtStartOfDay.getMillis)
but that's a bit ugly
回答1:
val Seq(expire, now) =
Seq(row.expireDate, new JodaDate).map(_.toDateTimeAtStartOfDay.getMillis)
回答2:
What you want (assuming you don't want to go the conversion-to-Seq
route) is Scalaz's Bifunctor instance for tuples (which isn't in the standard library). With it you can write the following:
scala> import scalaz._, Scalaz._
import scalaz._
import Scalaz._
scala> val cap = (_: String).toUpperCase
cap: String => java.lang.String = <function1>
scala> val removeLs = (_: String).replaceAll("l", "")
removeLs: String => java.lang.String = <function1>
scala> cap <-: ("hello", "world") :-> removeLs
res0: (java.lang.String, java.lang.String) = (HELLO,word)
Or, in your case:
val f = (_: JodaDate).toDateTimeAtStartOfDay.getMillis
val (expire, now) = f <-: (row.expireDate, new JodaDate) :-> f
回答3:
val Seq(a, b) =
Seq("a", "b").map(_.toUpperCase)
println("a, b = %s, %s".format(a, b)) // a, b = A, B
回答4:
If you want to keep the type safety of using a tuple (remember, when unapplying a Seq
, the compiler will not check the length), you can write a wrapper to add a function not available in the standard library, which will let you map over a tuple.
In the case of mapping over both elements using a single function, because a Tuple2[A, B]
has two type parameters, the key to making this work is to require evidence that A
and B
are the same type. To do this, require an implicit parameter of type B =:= A
; if the types are indeed equal, the compiler will supply a function of type B => A
.
class Tuple2Wrapper[A, B](t: (A, B)) {
def bimap[C, D](f: A => C, g: B => D): (C, D) = (f(t._1), g(t._2))
def <-:->[C](f: A => C)(implicit ev: B =:= A): (C, C) = bimap(f, f compose ev)
}
implicit def tuple2Tuple2Wrapper[A, B](t: (A, B)) = new Tuple2Wrapper(t)
scala> (1, 1) <-:-> (_ + 1)
res1: (Int, Int) = (2,2)
This could be done in a more general and useful way (applicable to more types than just Tuple2
), if implemented in terms of Scalaz's Bifunctor
trait.
来源:https://stackoverflow.com/questions/11363584/scala-zip-list-to-tuple