dsg*_*dsg 6 scala cartesian-product
这是一个后续:在Scala中将一组字符串扩展为笛卡尔积
你想要的想法是:
val sets = Set(Set("a","b","c"), Set("1","2"), Set("S","T"))
Run Code Online (Sandbox Code Playgroud)
并回来:
Set("a&1&S", "a&1&T", "a&2&S", ..., "c&2&T")
Run Code Online (Sandbox Code Playgroud)
一般解决方案是:
def combine[A](f:(A, A) => A)(xs:Iterable[Iterable[A]]) =
xs.reduceLeft { (x, y) => x.view.flatMap {a => y.map(f(a, _)) } }
Run Code Online (Sandbox Code Playgroud)
用法如下:
val expanded = combine{(x:String, y:String) => x + "&" + y}(sets).toSet
Run Code Online (Sandbox Code Playgroud)
从理论上讲,应该有一种方法来获取类型的输入Set[Set[A]]并获得一个Set[B].也就是说,在组合元素的同时转换类型.
一个示例用法是接受字符串集(如上所述)并输出其串联的长度.该f函数combine将一些形式:
(a:Int, b:String) => a + b.length
Run Code Online (Sandbox Code Playgroud)
我无法想出一个实现.有人有答案吗?
如果你真的想要你的组合器函数来进行映射,你可以使用a fold但是正如Craig指出的那样你必须提供一个种子值:
def combine[A, B](f: B => A => B, zero: B)(xs: Iterable[Iterable[A]]) =
xs.foldLeft(Iterable(zero)) {
(x, y) => x.view flatMap { y map f(_) }
}
Run Code Online (Sandbox Code Playgroud)
您需要这样的种子值的事实来自组合器/映射器函数类型(B, A) => B(或者,作为curried函数B => A => B).显然,要映射A你遇到的第一个,你将需要提供一个B.
通过使用Zero类型类,您可以使调用者更简单:
trait Zero[T] {
def zero: T
}
object Zero {
implicit object IntHasZero extends Zero[Int] {
val zero = 0
}
// ... etc ...
}
Run Code Online (Sandbox Code Playgroud)
然后该combine方法可以定义为:
def combine[A, B : Zero](f: B => A => B)(xs: Iterable[Iterable[A]]) =
xs.foldLeft(Iterable(implicitly[Zero[B]].zero)) {
(x, y) => x.view flatMap { y map f(_) }
}
Run Code Online (Sandbox Code Playgroud)
用法:
combine((b: Int) => (a: String) => b + a.length)(sets)
Run Code Online (Sandbox Code Playgroud)
Scalaz提供了一个Zero类型类,以及许多其他功能编程的好东西.
您遇到的问题是reduce(Left | Right)接受一个函数(A,A)=> A,它不允许您更改类型.你想要更像foldLeft的东西,它取(B,A)⇒B,允许你积累不同类型的输出.folds虽然需要种子值,但这里不能是空集合.你需要将xs分成头部和尾部,将头部迭代映射为Iterable [B],然后使用映射的头部,尾部和一些函数(B,A)=> B调用foldLeft.虽然看起来比它的价值更麻烦,所以我只是做前面的所有映射.
def combine[A, B](f: (B, B) => B)(g: (A) => B)(xs:Iterable[Iterable[A]]) =
xs.map(_.map(g)).reduceLeft { (x, y) => x.view.flatMap {a => y.map(f(a, _)) } }
val sets = Set(Set(1, 2, 3), Set(3, 4), Set(5, 6, 7))
val expanded = combine{(x: String, y: String) => x + "&" + y}{(i: Int) => i.toString}(sets).toSet
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1919 次 |
| 最近记录: |