有两种解决方案。首先是不要求容器是某个通用超类的子类,而是可以转换为一个(通过使用隐式函数参数)。如果容器已经是所需类型的子类,则只有一个预定义的标识转换,它只返回它。
import collection.mutable.Builder
import collection.TraversableLike
import collection.generic.CanBuildFrom
import collection.mutable.SeqLike
class Cartesian[T, ST[T], TT[S]](val ll: TT[ST[T]])(implicit cbf: CanBuildFrom[Nothing, T, ST[T]], seqLike: ST[T] => SeqLike[T, ST[T]], traversableLike: TT[ST[T]] => TraversableLike[ST[T], TT[ST[T]]]) extends Iterator[ST[T]] {
def combicount(): Int = (1 /: ll) (_ * _.length)
val last = combicount - 1
var iter = 0
override def hasNext(): Boolean = iter < last
override def next(): ST[T] = {
val res = combination (ll, iter, cbf())
iter += 1
res
}
def combination (xx: TT[ST[T]], i: Int, builder: Builder[T, ST[T]]): ST[T] =
if (xx.isEmpty) builder.result
else combination (xx.tail, i/xx.head.length, builder += xx.head (i % xx.head.length))
}
这类作品:
scala> new Cartesian[String, Vector, Vector](Vector(Vector("a"), Vector("xy"), Vector("AB")))
res0: Cartesian[String,Vector,Vector] = empty iterator
scala> new Cartesian[String, Array, Array](Array(Array("a"), Array("xy"), Array("AB")))
res1: Cartesian[String,Array,Array] = empty iterator
我需要明确地传递,因为错误https://issues.scala-lang.org/browse/SI-3343
有一点要注意的类型是,这是比使用存在类型比较好,因为调用迭代器上的下一个返回正确的类型,而不是Seq [Any]。
有几个缺点这里:
- 如果容器不是所需的类型的子类,它被转换为一个,这在性能
- 成本的算法是不完全通用。我们需要将类型转换为SeqLike或TraversableLike,才能使用这些类型提供的功能子集。所以制作一个转换函数可能会很棘手。
- 如果某些功能在不同的环境下可以有不同的解释,该怎么办?例如,矩形具有两个“长度”属性(宽度和高度)
现在为替代解决方案。我们注意到,我们并不真正关心的各类收藏品,只是他们的能力:
- TT应该有
foldLeft
,get(i: Int)
(获得头/尾)
- ST应有
length
,get(i: Int)
和生成器
所以我们可以编码这些:
trait HasGet[T, CC[_]] {
def get(cc: CC[T], i: Int): T
}
object HasGet {
implicit def seqLikeHasGet[T, CC[X] <: SeqLike[X, _]] = new HasGet[T, CC] {
def get(cc: CC[T], i: Int): T = cc(i)
}
implicit def arrayHasGet[T] = new HasGet[T, Array] {
def get(cc: Array[T], i: Int): T = cc(i)
}
}
trait HasLength[CC] {
def length(cc: CC): Int
}
object HasLength {
implicit def seqLikeHasLength[CC <: SeqLike[_, _]] = new HasLength[CC] {
def length(cc: CC) = cc.length
}
implicit def arrayHasLength[T] = new HasLength[Array[T]] {
def length(cc: Array[T]) = cc.length
}
}
trait HasFold[T, CC[_]] {
def foldLeft[A](cc: CC[T], zero: A)(op: (A, T) => A): A
}
object HasFold {
implicit def seqLikeHasFold[T, CC[X] <: SeqLike[X, _]] = new HasFold[T, CC] {
def foldLeft[A](cc: CC[T], zero: A)(op: (A, T) => A): A = cc.foldLeft(zero)(op)
}
implicit def arrayHasFold[T] = new HasFold[T, Array] {
def foldLeft[A](cc: Array[T], zero: A)(op: (A, T) => A): A = {
var i = 0
var result = zero
while (i < cc.length) {
result = op(result, cc(i))
i += 1
}
result
}
}
}
(严格地说,HasFold不requi自实施以来,红色是在长度方面和得到的,但我在这里补充它,因此算法将转化更干净)
现在的算法是:
class Cartesian[T, ST[_], TT[Y]](val ll: TT[ST[T]])(implicit cbf: CanBuildFrom[Nothing, T, ST[T]], stHasLength: HasLength[ST[T]], stHasGet: HasGet[T, ST], ttHasFold: HasFold[ST[T], TT], ttHasGet: HasGet[ST[T], TT], ttHasLength: HasLength[TT[ST[T]]]) extends Iterator[ST[T]] {
def combicount(): Int = ttHasFold.foldLeft(ll, 1)((a,l) => a * stHasLength.length(l))
val last = combicount - 1
var iter = 0
override def hasNext(): Boolean = iter < last
override def next(): ST[T] = {
val res = combination (ll, 0, iter, cbf())
iter += 1
res
}
def combination (xx: TT[ST[T]], j: Int, i: Int, builder: Builder[T, ST[T]]): ST[T] =
if (ttHasLength.length(xx) == j) builder.result
else {
val head = ttHasGet.get(xx, j)
val headLength = stHasLength.length(head)
combination (xx, j + 1, i/headLength, builder += stHasGet.get(head, (i % headLength)))
}
}
及用途:
scala> new Cartesian[String, Vector, List](List(Vector("a"), Vector("xy"), Vector("AB")))
res6: Cartesian[String,Vector,List] = empty iterator
scala> new Cartesian[String, Array, Array](Array(Array("a"), Array("xy"), Array("AB")))
res7: Cartesian[String,Array,Array] = empty iterator
斯卡拉斯可能已经为你预定了所有这些,不幸的是,我不太清楚它。
(我再次需要通过类型,因为推论并不推断正确的)
的好处是,该算法现在完全通用的,没有必要从Array到WrappedArray在隐式转换为了它的工作
锻炼; Tibial:定义的元组;-)
你可能想重新考虑你的方法,并从头[这个问题](HTTP以下雷克斯·科尔的优秀建议://开头计算器。 COM /问题/ 5410846 /怎么办,我申请最皮条客,我的图书馆模式到斯卡拉的集合)。 – 2011-05-26 14:34:26
谢谢你的链接。我希望我有时间深入阅读,并在周末或今天全部尝试。看起来很有希望。 – 2011-05-27 12:19:33