Scala 中结合的笛卡尔积和映射
这是以下内容的后续内容: 将一组字符串集合展开为笛卡尔积在Scala中的
想法是你想要获取:
val sets = Set(Set("a","b","c"), Set("1","2"), Set("S","T"))
并返回:
Set("a&1&S", "a&1&T", "a&2&S", ..., "c&2&T")
一般的解决方案是:
def combine[A](f:(A, A) => A)(xs:Iterable[Iterable[A]]) =
xs.reduceLeft { (x, y) => x.view.flatMap {a => y.map(f(a, _)) } }
使用如下:
val expanded = combine{(x:String, y:String) => x + "&" + y}(sets).toSet
理论上,应该有一种方法来获取Set[Set[A]]<类型的输入/code> 并返回一个
Set[B]
。即在组合元素的同时进行类型转换。
一个示例用法是接收字符串集(如上所述)并输出它们连接的长度。 combine
中的 f
函数具有以下形式:
(a:Int, b:String) => a + b.length
我无法提出一个实现。有人有答案吗?
This is a followup to: Expand a Set of Sets of Strings into Cartesian Product in Scala
The idea is you want to take:
val sets = Set(Set("a","b","c"), Set("1","2"), Set("S","T"))
and get back:
Set("a&1&S", "a&1&T", "a&2&S", ..., "c&2&T")
A general solution is:
def combine[A](f:(A, A) => A)(xs:Iterable[Iterable[A]]) =
xs.reduceLeft { (x, y) => x.view.flatMap {a => y.map(f(a, _)) } }
used as follows:
val expanded = combine{(x:String, y:String) => x + "&" + y}(sets).toSet
Theoretically, there should be a way to take input of type Set[Set[A]]
and get back a Set[B]
. That is, to convert the type while combining the elements.
An example usage would be to take in sets of strings (as above) and output the lengths of their concatenation. The f
function in combine
would something of the form:
(a:Int, b:String) => a + b.length
I was not able to come up with an implementation. Does anyone have an answer?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果您确实希望组合器函数执行映射,则可以使用
fold
但作为 Craig 指出 你必须提供一个种子值:你需要这样一个种子值的事实来自于组合器/映射器函数类型
( B、A)=> B
(或者,作为柯里化函数,B => A => B
)。显然,要映射您遇到的第一个A
,您需要提供B
。您可以通过使用
Zero
类型类使调用者变得更简单:然后
combine
方法可以定义为:用法:
Scalaz 提供了一个
Zero
类型类,以及许多其他用于函数式编程的好东西。If you really want your combiner function to do the mapping, you can use a
fold
but as Craig pointed out you'll have to provide a seed value:The fact that you need such a seed value follows from the combiner/mapper function type
(B, A) => B
(or, as a curried function,B => A => B
). Clearly, to map the firstA
you encounter, you're going to need to supply aB
.You can make it somewhat simpler for callers by using a
Zero
type class:Then the
combine
method can be defined as:Usage:
Scalaz provides a
Zero
type class, along with a lot of other goodies for functional programming.您遇到的问题是,reduce(Left|Right) 接受一个函数 (A, A) => A 不允许您更改类型。您想要更像foldLeft 的东西,它采用(B, A) ⇒ B,允许您累积不同类型的输出。不过,folds 需要一个种子值,这里不能是空集合。您需要将 xs 分成头部和尾部,将头部可迭代映射为 Iterable[B],然后使用映射的头部、尾部和某个函数 (B, A) => 调用 FoldLeft B. 这似乎比它值得的麻烦更多,所以我只是预先完成所有映射。
The problem that you're running into is that reduce(Left|Right) takes a function (A, A) => A which doesn't allow you to change the type. You want something more like foldLeft which takes (B, A) ⇒ B, allowing you to accumulate an output of a different type. folds need a seed value though, which can't be an empty collection here. You'd need to take xs apart into a head and tail, map the head iterable to be Iterable[B], and then call foldLeft with the mapped head, the tail, and some function (B, A) => B. That seems like more trouble than it's worth though, so I'd just do all the mapping up front.