用于转换任意大小的元组的多态函数
Polymorphic function to convert tuples of arbitrary size
我想创建一个多态函数,将各种大小的元组列表作为参数,return 一个相同类型的列表。因此,函数内的代码也应该进行调整。这里有一个例子来解释我的问题和我的目标:
val l2 = List( ("1","2"), ("3","4"))
val l3 = List( ("1","2","3"), ("4","5","6"))
val k2 = List( ("1","3"), ("5","7"))
val k3 = List( ("1","3","5"), ("7","9","11"))
def convertTuple2 ( l : List[(String,String)] ) : List[(Int,Int)] = {
if (l.contains("1","2")) l.map{ case (a,b) => (a.toInt+10, b.toInt+10) }
else l.map{ case (a,b) => (a.toInt, b.toInt) }
}
def convertTuple3 ( l : List[(String,String,String)] ) : List[(Int,Int,Int)] = {
if (l.contains("1","2","3")) l.map{ case (a,b,c) => (a.toInt+10, b.toInt+10, c.toInt+10)}
else l.map{ case (a,b,c) => (a.toInt, b.toInt, c.toInt) }
}
val l2converted = convertTuple2(l2)
val l3converted = convertTuple3(l3)
val k2converted = convertTuple2(k2)
val k3converted = convertTuple3(k3)
println(l2converted.mkString(",")) //printing (11,12),(13,14)
println(l3converted.mkString(",")) //printing (11,12,13),(14,15,16)
println(k2converted.mkString(",")) //printing (1,3),(5,7)
println(k3converted.mkString(",")) //printing (1,3,5),(7,9,11)
换句话说,如何创建一个既像 convertTuple2(...)
和 convertTuple3(...)
又可能像 convertTupleN(...)
的独特函数?
这意味着 l.contains(...)
和模式匹配 { case ... => ... }
元素也必须根据输入列表中元组的大小进行调整。
什么是简单、优雅且高效的解决方案?
尝试
import shapeless.{HList, Nat, Poly1}
import shapeless.ops.hlist.Tupler
import shapeless.ops.tuple.{Length, Mapper}
import shapeless.ops.nat.ToInt
import shapeless.syntax.nat._
import shapeless.syntax.std.tuple._
import shapeless.poly.->
import shapeless.nat._
object toStringPoly extends Poly1 {
implicit def `case`[N <: Nat](implicit
toInt: ToInt[N]
): Case.Aux[N, String] = at(_ => toInt().toString)
}
object toIntPoly extends (String -> Int)(_.toInt)
object toIntPoly1 extends (String -> Int)(s => s.toInt + 10)
def convertTuple[A <: Product,
N <: Nat,
L <: HList,
B <: Product,
C <: Product](l: List[A])(implicit
length: Length.Aux[A, N],
range: (_1 *--* N) { type Out = L },
tupler: Tupler.Aux[L, B],
toStringMapper: Mapper[B, toStringPoly.type],
toIntMapper: Mapper.Aux[A, toIntPoly.type, C],
toIntMapper1: Mapper.Aux[A, toIntPoly1.type, C],
) : List[C] =
if (l.contains(range().tupled.map(toStringPoly)))
l.map(_.map(toIntPoly1))
else l.map(_.map(toIntPoly))
或
import scala.collection.immutable.IndexedSeq
import shapeless.{HList, Nat, unexpected}
import shapeless.ops.hlist.Tupler
import shapeless.ops.tuple.{Length, Mapper}
import shapeless.ops.nat.ToInt
import shapeless.ops.traversable.ToSizedHList
import shapeless.syntax.std.tuple._
import shapeless.poly.->
object toIntPoly extends (String -> Int)(_.toInt)
object toIntPoly1 extends (String -> Int)(s => s.toInt + 10)
def convertTuple[A <: Product, N <: Nat, L <: HList, C <: Product](l: List[A])(implicit
length: Length.Aux[A, N],
toInt: ToInt[N],
toSizedHList: ToSizedHList.Aux[IndexedSeq, String, N, Option[L]],
tupler: Tupler[L],
toIntMapper: Mapper.Aux[A, toIntPoly.type, C],
toIntMapper1: Mapper.Aux[A, toIntPoly1.type, C],
) : List[C] =
if (l.contains(toSizedHList((1 to toInt()).map(_.toString)).getOrElse(unexpected).tupled))
l.map(_.map(toIntPoly1))
else l.map(_.map(toIntPoly))
我想创建一个多态函数,将各种大小的元组列表作为参数,return 一个相同类型的列表。因此,函数内的代码也应该进行调整。这里有一个例子来解释我的问题和我的目标:
val l2 = List( ("1","2"), ("3","4"))
val l3 = List( ("1","2","3"), ("4","5","6"))
val k2 = List( ("1","3"), ("5","7"))
val k3 = List( ("1","3","5"), ("7","9","11"))
def convertTuple2 ( l : List[(String,String)] ) : List[(Int,Int)] = {
if (l.contains("1","2")) l.map{ case (a,b) => (a.toInt+10, b.toInt+10) }
else l.map{ case (a,b) => (a.toInt, b.toInt) }
}
def convertTuple3 ( l : List[(String,String,String)] ) : List[(Int,Int,Int)] = {
if (l.contains("1","2","3")) l.map{ case (a,b,c) => (a.toInt+10, b.toInt+10, c.toInt+10)}
else l.map{ case (a,b,c) => (a.toInt, b.toInt, c.toInt) }
}
val l2converted = convertTuple2(l2)
val l3converted = convertTuple3(l3)
val k2converted = convertTuple2(k2)
val k3converted = convertTuple3(k3)
println(l2converted.mkString(",")) //printing (11,12),(13,14)
println(l3converted.mkString(",")) //printing (11,12,13),(14,15,16)
println(k2converted.mkString(",")) //printing (1,3),(5,7)
println(k3converted.mkString(",")) //printing (1,3,5),(7,9,11)
换句话说,如何创建一个既像 convertTuple2(...)
和 convertTuple3(...)
又可能像 convertTupleN(...)
的独特函数?
这意味着 l.contains(...)
和模式匹配 { case ... => ... }
元素也必须根据输入列表中元组的大小进行调整。
什么是简单、优雅且高效的解决方案?
尝试
import shapeless.{HList, Nat, Poly1}
import shapeless.ops.hlist.Tupler
import shapeless.ops.tuple.{Length, Mapper}
import shapeless.ops.nat.ToInt
import shapeless.syntax.nat._
import shapeless.syntax.std.tuple._
import shapeless.poly.->
import shapeless.nat._
object toStringPoly extends Poly1 {
implicit def `case`[N <: Nat](implicit
toInt: ToInt[N]
): Case.Aux[N, String] = at(_ => toInt().toString)
}
object toIntPoly extends (String -> Int)(_.toInt)
object toIntPoly1 extends (String -> Int)(s => s.toInt + 10)
def convertTuple[A <: Product,
N <: Nat,
L <: HList,
B <: Product,
C <: Product](l: List[A])(implicit
length: Length.Aux[A, N],
range: (_1 *--* N) { type Out = L },
tupler: Tupler.Aux[L, B],
toStringMapper: Mapper[B, toStringPoly.type],
toIntMapper: Mapper.Aux[A, toIntPoly.type, C],
toIntMapper1: Mapper.Aux[A, toIntPoly1.type, C],
) : List[C] =
if (l.contains(range().tupled.map(toStringPoly)))
l.map(_.map(toIntPoly1))
else l.map(_.map(toIntPoly))
或
import scala.collection.immutable.IndexedSeq
import shapeless.{HList, Nat, unexpected}
import shapeless.ops.hlist.Tupler
import shapeless.ops.tuple.{Length, Mapper}
import shapeless.ops.nat.ToInt
import shapeless.ops.traversable.ToSizedHList
import shapeless.syntax.std.tuple._
import shapeless.poly.->
object toIntPoly extends (String -> Int)(_.toInt)
object toIntPoly1 extends (String -> Int)(s => s.toInt + 10)
def convertTuple[A <: Product, N <: Nat, L <: HList, C <: Product](l: List[A])(implicit
length: Length.Aux[A, N],
toInt: ToInt[N],
toSizedHList: ToSizedHList.Aux[IndexedSeq, String, N, Option[L]],
tupler: Tupler[L],
toIntMapper: Mapper.Aux[A, toIntPoly.type, C],
toIntMapper1: Mapper.Aux[A, toIntPoly1.type, C],
) : List[C] =
if (l.contains(toSizedHList((1 to toInt()).map(_.toString)).getOrElse(unexpected).tupled))
l.map(_.map(toIntPoly1))
else l.map(_.map(toIntPoly))