Scala中笛卡尔积与映射的组合

Scala中笛卡尔积与映射的组合,scala,cartesian-product,Scala,Cartesian Product,以下是以下内容: 这个想法是你想要: 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.reduceL

以下是以下内容:

这个想法是你想要:

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[a]
的输入,然后返回a
Set[B]
。也就是说,在组合元素时转换类型

一个示例用法是接收字符串集(如上所述)并输出它们的串联长度。
combine
中的
f
函数的形式如下:

(a:Int, b:String) => a + b.length 

我没能想出一个实现方案。有人有答案吗?

您遇到的问题是reduce(左|右)使用了一个函数(a,a)=>a,它不允许您更改类型。你想要更像foldLeft的东西,需要(B,A)⇒ B、 允许您累积不同类型的输出。折叠需要一个种子值,这里不能是空集合。您需要将xs分解为head和tail,将head iterable映射为iterable[B],然后使用映射的head、tail和一些函数(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

如果您确实希望组合器函数进行映射,则可以使用
折叠
,但您必须提供种子值:

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(_) } 
    }
您需要这样一个种子值的事实来自组合器/映射器函数类型
(B,a)=>B
(或者,作为一个常用函数,
B=>a=>B
)。显然,要映射您遇到的第一个
A
,您需要提供一个
B

通过使用
Zero
类型类,可以使调用者的操作稍微简单一些:

trait Zero[T] {
   def zero: T
}
object Zero {
   implicit object IntHasZero extends Zero[Int] {
      val zero = 0
   }
   // ... etc ...
}
然后,
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(_) }
    }
用法:

combine((b: Int) => (a: String) => b + a.length)(sets)
提供了一个
Zero
类型类,以及许多其他函数编程的好东西。

如果字符串的Zero为“”,并且组合器函数在字符串之间放置了“&”,则此解决方案将在输出中每个字符串的前面产生一个额外的“&”(返回OP)。