在Scala中,有没有一种简单的方法将案例类转换为元组?

发布于 2024-12-15 04:22:13 字数 207 浏览 3 评论 0原文

有没有一种简单的方法将案例类转换为元组?

当然,我可以轻松编写样板代码来执行此操作,但我的意思是没有样板。

我真正追求的是一种轻松地按字典顺序排列案例类的方法。我可以通过导入 scala.math.Ordering.Implicits._ 来实现元组的目标,瞧,我的元组已经为它们定义了排序。但 scala.math.Ordering 中的隐含内容通常不适用于案例类。

Is there an easy way to convert a case class into a tuple?

I can, of course, easily write boilerplate code to do this, but I mean without the boilerplate.

What I'm really after is a way to easily make a case class lexicographically Ordered. I can achieve the goal for tuples by importing scala.math.Ordering.Implicits._, and voila, my tuples have an Ordering defined for them. But the implicits in scala.math.Ordering don't work for case classes in general.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

凌乱心跳 2024-12-22 04:22:13

在伴生对象中调用 unapply().get 怎么样?

case class Foo(foo: String, bar: Int)

val (str, in) = Foo.unapply(Foo("test", 123)).get
// str: String = test
// in: Int = 123

How about calling unapply().get in the companion object?

case class Foo(foo: String, bar: Int)

val (str, in) = Foo.unapply(Foo("test", 123)).get
// str: String = test
// in: Int = 123
晌融 2024-12-22 04:22:13

Shapeless 会为你做到这一点。

  import shapeless._
  import shapeless.syntax.std.product._

  case class Fnord(a: Int, b: String)

  List(Fnord(1, "z - last"), Fnord(1, "a - first")).sortBy(_.productElements.tupled)

获取

res0: List[Fnord] = List(Fnord(1,a - first), Fnord(1,z - last))

productElements 将案例类转换为Shapeless HList:

scala> Fnord(1, "z - last").productElements
res1: Int :: String :: shapeless.HNil = 1 :: z - last :: HNil

并且HList 使用#tupled 转换为元组:

scala> Fnord(1, "z - last").productElements.tupled
res2: (Int, String) = (1,z - last)

性能可能很糟糕,因为您不断进行转换。您可能会将所有内容都转换为元组形式,对其进行排序,然后使用诸如 (Fnord.apply _).tupled 之类的内容将其转换回来。

Shapeless will do this for you.

  import shapeless._
  import shapeless.syntax.std.product._

  case class Fnord(a: Int, b: String)

  List(Fnord(1, "z - last"), Fnord(1, "a - first")).sortBy(_.productElements.tupled)

Gets

res0: List[Fnord] = List(Fnord(1,a - first), Fnord(1,z - last))

productElements turns a case class into a Shapeless HList:

scala> Fnord(1, "z - last").productElements
res1: Int :: String :: shapeless.HNil = 1 :: z - last :: HNil

And HLists are converted to tuples with #tupled:

scala> Fnord(1, "z - last").productElements.tupled
res2: (Int, String) = (1,z - last)

Performance is likely to be horrible, since you're constantly converting. You'd probably convert everything to the tupled form, sort that, then convert it back using something like (Fnord.apply _).tupled.

酷炫老祖宗 2024-12-22 04:22:13

Scala 3 对案例类和元组之间的转换提供一流的支持:

scala> case class Foo(foo: String, bar: Int)
// defined case class Foo

scala> Tuple.fromProductTyped(Foo("a string", 1))
val res0: (String, Int) = (a string,1)

scala> summon[deriving.Mirror.ProductOf[Foo]].fromProduct(res0)
val res1: deriving.Mirror.ProductOf[Foo]#MirroredMonoType = Foo(a string,1)

Scala 3 has first class support for conversions between case classes and tuples:

scala> case class Foo(foo: String, bar: Int)
// defined case class Foo

scala> Tuple.fromProductTyped(Foo("a string", 1))
val res0: (String, Int) = (a string,1)

scala> summon[deriving.Mirror.ProductOf[Foo]].fromProduct(res0)
val res1: deriving.Mirror.ProductOf[Foo]#MirroredMonoType = Foo(a string,1)
无所谓啦 2024-12-22 04:22:13

在尝试做同样的事情时遇到了这个旧线程。我最终选择了这个解决方案:

case class Foo(foo: String, bar: Int)

val testFoo = Foo("a string", 1)

val (str, in) = testFoo match { case Foo(f, b) => (f, b) }

Came across this old thread while attempting to do this same thing. I eventually settled on this solution:

case class Foo(foo: String, bar: Int)

val testFoo = Foo("a string", 1)

val (str, in) = testFoo match { case Foo(f, b) => (f, b) }
<逆流佳人身旁 2024-12-22 04:22:13

您可以尝试扩展 ProductN 特征,对于 N=1-22,TupleN 扩展了该特征。它会给你很多元组语义,比如_1_2等方法。根据您使用类型的方式,这可能就足够了,而无需创建实际的元组。

You might try extending the ProductN trait, for N=1-22, which TupleN extends. It will give you a lot of Tuple semantics, like the _1, _2, etc. methods. Depending on you how you use your types, this might be sufficient without creating an actual Tuple.

枫林﹌晚霞¤ 2024-12-22 04:22:13

好吧,这不是一个通用的解决方案,但遗憾的是,对我来说最优雅的方法是在案例类本身中添加 toTuple 。至少在我们迁移到 Scala 3 之前是这样。

case class Foo(foo: String, bar: Int) {
  val toTuple: (foo, bar) = (foo, bar)
}

Well, it's not a general solution, but sadly the most elegant way for me is to add the toTuple inside the case class itself. At least before we migrate to Scala 3.

case class Foo(foo: String, bar: Int) {
  val toTuple: (foo, bar) = (foo, bar)
}
旧话新听 2024-12-22 04:22:13

特别是对于 Scala 3,这是我一直在使用的解决方案(基于此 文章):

package org.public_domain

import scala.deriving.Mirror

//Based on code snippet found here:
//  https://taig.medium.com/converting-between-tuples-and-case-classes-in-scala-3-7079ccedf4c0
object TupleUtils:
  def to[A <: Product](value: A)(using
      mirror: Mirror.ProductOf[A]
  ): mirror.MirroredElemTypes = Tuple.fromProductTyped(value)

  def from[A](value: Product)(using
      mirror: Mirror.ProductOf[A],
      ev: value.type <:< mirror.MirroredElemTypes
  ): A = mirror.fromProduct(value)

Specifically for Scala 3, here's a solution I've been using (based on a code snippet from this article):

package org.public_domain

import scala.deriving.Mirror

//Based on code snippet found here:
//  https://taig.medium.com/converting-between-tuples-and-case-classes-in-scala-3-7079ccedf4c0
object TupleUtils:
  def to[A <: Product](value: A)(using
      mirror: Mirror.ProductOf[A]
  ): mirror.MirroredElemTypes = Tuple.fromProductTyped(value)

  def from[A](value: Product)(using
      mirror: Mirror.ProductOf[A],
      ev: value.type <:< mirror.MirroredElemTypes
  ): A = mirror.fromProduct(value)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文