【问题标题】:Scala convert List with unknown length to Tuple so pass it to Slick map clauseScala将未知长度的List转换为Tuple,然后将其传递给Slick map子句
【发布时间】:2017-05-28 23:14:51
【问题描述】:

我在 scala 代码中有 List,例如我可以从特定方法接收,并且此列表的长度可能会不时变化,我的目标是将此 List 转换为 Tuple 并具有相同的元素计数:

val lst = someComputationHere()
val tupleLst = lstToTuple(lst)

澄清

//if lst.length = 2 --> Tuple2
//if lst.length = 3 --> Tuple3
//if lst.length = 4 --> Tuple4
...............

//if lst.length = N --> TupleN
and so on

附言我宁愿不使用反射来解决这个问题

UPD 我的目标是将具有上述属性的传递列表传递给Slickmap clause。让我们考虑下一个代码快照:

query.map{ p=> (p.value1, p.value2, ... , p.valueN)}

这个值的数量是动态的,我将这个values 介绍给列表:

  val lst = someComputationHere()
    val tuples = toTuples(lst)//Problem is here
    query.map{_ => tuples}

问题描述query.map{} - 不通过列表,因此,我必须将具有可变长度 N 的 lst 转换为具有 N 个元素的 Tuple

【问题讨论】:

  • 你这样做的目的是什么?
  • 各种元组的常见超类型是Product。 IE。 val tupleLst: Product = ??? 这给了你一个无类型的迭代器。你希望用它做什么?
  • @ pedrofurla 我需要进行此转换,因此将 List 放在 Tuple 的映射子句中 Slick 以便获取具有动态可变数量的参数。不过对 Slick 来说没关系,让我们只从 Scala 代码的角度考虑这个问题,没有任何第三方库。
  • 你如何处理元组?如果您只是将它们直接传递给一系列函数TupleN => SomeType,那么您可以通过在列表上匹配并根据长度立即调度相关元组来创建一个函数List[T] => SomeType

标签: scala list tuples slick


【解决方案1】:

我不知道 Slick,但如果它只处理元组,这对我来说似乎是一个糟糕的设计选择。即使在 Scala 2.12 中,也没有为大于 22 的元组预定义类型,尽管 Scala 会综合创建它们。所以你最好的选择是一个大的模式匹配,包括你需要支持的所有元素:

def toTuple[A](lst: List[A]): Product = lst match {
  case _1 :: Nil             => Tuple1(_1)
  case _1 :: _2 :: Nil       => Tuple2(_1, _2)
  case _1 :: _2 :: _3 :: Nil => Tuple3(_1, _2, _3)
  ...
}

【讨论】:

  • 如果我需要完全采用 TupleN 而不是 Product 类型,我无法在您的 toTuple 实现中将 Product 转换为 TupleN
  • 没有TupleN这样的东西
  • @pacman 您正试图采用在运行时定义的东西并对其强制执行只能在编译时定义的东西。这是您希望实现的最佳解决方案。
  • @0__ 我的意思是一般情况,其中 N 是 lst 的长度
  • @pacman 你只能在运行时知道 N(这就是wheaties 所说的)。 List 不会在类型中编码其长度。所以你不能根据长度来做类型。如果您可以将 List 更改为编码长度的类型,那么您可能会更幸运。我相信 Shapeless 图书馆有这样的东西。我仍然认为您的情况不正确。 Slick 要么接受任何元组(然后它可能会要求一个 Product),要么它要求一个特定的元组(然后你只需要验证列表长度)。
【解决方案2】:

通常您不能这样做,因为元组访问方法_1_2 等具有编译时检查(列表大小在编译时未定义)。但是所有的元组都实现了 Product trait,你可以通过它的顺序来获取元素:

(1, 2, 3).productElement(2) // returns 2

您可以尝试编写带有下一个签名的方法(可能使用宏)

List[T] => Product

方法将返回 TupleN 其中 N 是列表大小。例如,非常原始的实现:

list.length match {
  case 1 => (list(0))
  case 2 => (list(0), list(1))
  ...
  case 22 => (list(0), list(1), ... ,list(21))
  case _ => throw some exception...
}

在运行时之后,您可以尝试将您的产品转换为具体的 TupleN 类型。但这一切似乎都很肮脏。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-24
    • 1970-01-01
    • 1970-01-01
    • 2016-07-21
    • 1970-01-01
    • 1970-01-01
    • 2019-11-20
    相关资源
    最近更新 更多