如何在scala中编写元组范围函数?
我想要下面的函数如何在scala中编写元组范围函数?,scala,tuples,scala-collections,Scala,Tuples,Scala Collections,我想要下面的函数 范围((1,1)、(2,2))返回哪个 Seq[(Int,Int)]((1,1),(1,2),(2,1),(2,2)) 它是一维范围的模拟,具有1到2 该函数应适用于任何scala元组(即Tuple2、Tuple3、Tuple4等),并且是类型安全的 我试过了 def tupleRange[T <: Product](t1:T, t2:T):Seq[T] = { assert(t1.productArity == t2.productArity)
范围((1,1)、(2,2))
返回哪个
Seq[(Int,Int)]((1,1),(1,2),(2,1),(2,2))
它是一维范围的模拟,具有1到2
该函数应适用于任何scala元组(即Tuple2、Tuple3、Tuple4等),并且是类型安全的
我试过了
def tupleRange[T <: Product](t1:T, t2:T):Seq[T] = {
assert(t1.productArity == t2.productArity)
def tail(t:Product):Product = sys.error("todo");
def join(i:Int, p:Product):T = sys.error("todo");
for(
v <- t1.productElement(0).asInstanceOf[Int] to t2.productElement(0).asInstanceOf[Int];
v2 <- tupleRange(tail(t1), tail(t2)))
yield join(v,v2)
}
implicit def range[T <:Product](p1:T) = new { def to(p2:T) = tupleRange(p1,p2)}
def tupleRange[T对于每个元组arity,您需要一个不同的版本(但是您可以使用预处理器来生成每个版本)。下面是我的实现(它是惰性的):
您可以将其用作:
scala> range2( 1 to 10 )
res3: Seq[(Int, Int)] = Stream((1,1), ?)
首先,考虑这一点:
scala> 1 to 10
res0: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
对于元组来说有这样的东西会很好,对吗
class RangedTuple(t: Tuple2[Int, Int]) {
def to(t2: Tuple2[Int, Int]) = {
(t, t2) match {
case ((a1: Int, a2: Int), (b1: Int, b2: Int)) => {
(for {
i <- a1 to b1
} yield (a1 to b1).map(j => (i, j))).flatMap(k => k)
}
}
}
}
implicit def t2rt(t: Tuple2[Int, Int]) = new RangedTuple(t)
这对你有用吗?我建议使用@ziggystar上面建议的方法。使用List[Int]
而不是Int
s的元组
scala> import scalaz._
import scalaz._
scala> import Scalaz._
import Scalaz._
scala> def range(xs: List[Int], ys: List[Int]): List[List[Int]] = {
| (xs, ys).zipped.map((x, y) => List.range(x, y + 1)).sequence
| }
range: (xs: List[Int], ys: List[Int])List[List[Int]]
scala> range(List(1, 2, 4), List(2, 5, 6))
res29: List[List[Int]] = List(List(1, 2, 4), List(1, 2, 5), List(1, 2, 6),
List(1, 3, 4), List(1, 3, 5), List(1, 3, 6), List(1, 4, 4), List(1, 4, 5),
List(1, 4, 6), List(1, 5, 4), List(1, 5, 5), List(1, 5, 6), List(2, 2, 4),
List(2, 2, 5), List(2, 2, 6), List(2, 3, 4), List(2, 3, 5), List(2, 3, 6),
List(2, 4, 4), List(2, 4, 5), List(2, 4, 6), List(2, 5, 4), List(2, 5, 5),
List(2, 5, 6))
此实现假定xs
和ys
是有序的,并且具有相同的长度。简单的方法是大量剪切和粘贴,为每个元组数组重载方法:
def range(r: (Int, Int), s: (Int, Int)) =
for { p1 <- r._1 to s._1
p2 <- r._2 to s._2 } yield (p1, p2)
def range(r: (Int, Int, Int), s: (Int, Int, Int)) =
for { p1 <- r._1 to s._1
p2 <- r._2 to s._2
p3 <- r._3 to s._3 } yield (p1, p2, p3)
def range(r: (Int, Int, Int, Int), s: (Int, Int, Int, Int)) =
for // etc up to 22
似乎有效:
scala> range((1,2,4), (2,5,6))
res66: List[Product with Serializable] = List((1,2,4), (1,2,5), (1,2,6),
(1,3,4), (1,3,5), (1,3,6), (1,4,4), (1,4,5), (1,4,6), (1,5,4), (1,5,5),
(1,5,6), (2,2,4), (2,2,5), (2,2,6), (2,3,4), (2,3,5), (2,3,6), (2,4,4),
(2,4,5), (2,4,6), (2,5,4), (2,5,5), (2,5,6))
您的基本问题是,由于Scala是静态类型的,因此该方法需要有一个返回类型,因此您永远不能有一个方法同时返回Seq[(Int,Int)]
和Seq[(Int,Int,Int)]
和元组的所有其他算术。您最好使用覆盖所有输出的最接近类型,在本例中为可序列化的产品。
当然可以对结果进行转换,例如res0.map(u.asInstanceOf[(Int,Int,Int)])
像第一个例子中那样重载方法可以为每个arity提供不同的返回类型,因此不需要进行任何强制转换。使用迭代器,使用两个Seq而不是两个元组进行初始化怎么样
这是一本书
用法:
scala> val test = rangeIterator (Seq(1, 1), Seq(2, 2))
test: Cartesian = non-empty iterator
scala> test.toList
res38: List[Seq[_]] = List(List(1, 1), List(2, 1), List(1, 2), List(2, 2))
scala> val test = rangeIterator (Seq(1, 0, 9), Seq(2, 2, 11))
test: Cartesian = non-empty iterator
scala> test.toList
res43: List[Seq[_]] = List(List(1, 0, 9), List(2, 0, 9), List(1, 1, 9), List(2, 1, 9), List(1, 2, 9), List(2, 2, 9), List(1, 0, 10), List(2, 0, 10), List(1, 1, 10), List(2, 1, 10), List(1, 2, 10), List(2, 2, 10), List(1, 0, 11), List(2, 0, 11), List(1, 1, 11), List(2, 1, 11), List(1, 2, 11), List(2, 2, 11))
第二行中的类型签名应该是Seq[(Int,Int)]
,否?在一般情况下,“对于任何元组(arity)”,函数都不起作用。元组不会泛化它们的大小。既然您强制每个元组元素都具有相同的类型,为什么不选择一个集合呢?@ziggystar您是对的,糟糕的设计会导致实现中出现问题为什么要生成映射?只需在a2
到b2
之间添加第二个生成器。此外,这是错误的。如果a1!=a2
或b1!=b2
,您将得到错误的结果(尽管这很容易修复)。
def range(p1: Product, p2: Product) = {
def toList(t: Product): List[Int] =
t.productIterator.toList.map(_.asInstanceOf[Int])
def toProduct(lst: List[Int]) = lst.size match {
case 1 => Tuple1(lst(0))
case 2 => Tuple2(lst(0), lst(1))
case 3 => Tuple3(lst(0), lst(1), lst(2))
//etc up to 22
}
def go(xs: List[Int], ys: List[Int]): List[List[Int]] = {
if(xs.size == 1 || ys.size == 1) (xs.head to ys.head).toList.map(List(_))
else (xs.head to ys.head).toList.flatMap(i => go(xs.tail, ys.tail).map(i :: _))
}
go(toList(p1), toList(p2)) map toProduct
}
scala> range((1,2,4), (2,5,6))
res66: List[Product with Serializable] = List((1,2,4), (1,2,5), (1,2,6),
(1,3,4), (1,3,5), (1,3,6), (1,4,4), (1,4,5), (1,4,6), (1,5,4), (1,5,5),
(1,5,6), (2,2,4), (2,2,5), (2,2,6), (2,3,4), (2,3,5), (2,3,6), (2,4,4),
(2,4,5), (2,4,6), (2,5,4), (2,5,5), (2,5,6))
def rangeIterator (froms: Seq[Int], tos: Seq[Int]) = {
def range (froms: Seq[Int], tos: Seq[Int]) : Seq[Seq[Int]] =
if (froms.isEmpty) Nil else
Seq (froms.head to tos.head) ++ range (froms.tail, tos.tail)
new Cartesian (range (froms, tos))
}
scala> val test = rangeIterator (Seq(1, 1), Seq(2, 2))
test: Cartesian = non-empty iterator
scala> test.toList
res38: List[Seq[_]] = List(List(1, 1), List(2, 1), List(1, 2), List(2, 2))
scala> val test = rangeIterator (Seq(1, 0, 9), Seq(2, 2, 11))
test: Cartesian = non-empty iterator
scala> test.toList
res43: List[Seq[_]] = List(List(1, 0, 9), List(2, 0, 9), List(1, 1, 9), List(2, 1, 9), List(1, 2, 9), List(2, 2, 9), List(1, 0, 10), List(2, 0, 10), List(1, 1, 10), List(2, 1, 10), List(1, 2, 10), List(2, 2, 10), List(1, 0, 11), List(2, 0, 11), List(1, 1, 11), List(2, 1, 11), List(1, 2, 11), List(2, 2, 11))