【问题标题】:Scala pairs using map and flattenScala 对使用 map 和 flatten
【发布时间】:2023-10-29 05:49:01
【问题描述】:

我正在解决一个问题,以获取两个列表,例如 (1,2,3) 和 (a,b) 并返回一个列表 ((1,a)(1,b)(2,a) (2,b)(3,a)(3,b)) 仅使用映射和展平。

这个问题需要我定义一个函数如下:

def product[A](xs: List[A], ys: List[A])= {

并在这个函数中得到结果。我对 Scala 比较陌生,并且习惯于 python 和 java 之类的语言。

我已经走到这一步了:

def product[A](xs: List[A], ys: List[A])= {  
    for(y <- ys){
   println(xs.map(x=> (x,y)))  
    }
  }

这将返回如下内容:

列表((1,a), (2,a), (3,a))

列表((1,b), (2,b), (3,b))

我不确定现在如何组合这些列表。在 python 中,我会做一些事情,比如创建一个新的列表变量,将这两个列表都附加到该列表中,然后将其展平,这样我就有一个列表。但是,我对 scala 感到相当困惑,因为似乎不允许我在函数中定义新变量。此时如何合并这些列表并将它们展平?

【问题讨论】:

    标签: list scala mapping flatten


    【解决方案1】:

    你可以用理解来解决它。实际上是syntactic sugar 对应mapflatMap

    def product[A](xs: List[A], ys: List[A])= {
        for {
          x <- xs
          y <- ys
        } yield {
          x -> y
        }
    }
    

    For-comprehensions 是实现此目的的 Scala 惯用方式。它更具可读性和可维护性,底层操作仍然是mapflatMap。事实上,即使对于不是集合但仍有mapflatMap 的类型,也很常见用于推导式(Futures、Options、Trys 等)

    编辑

    如果您想继续使用您的解决方案并保存列表并将它们合并,您必须删除 println 并添加 yield,然后展平创建的主列表:

    def product[A](xs: List[A], ys: List[A]) = {
      for (y <- ys) yield {
        xs.map(x => (x, y))
      }
    }
    
    val res = product(List(1, 2, 3), List("a", "b"))
    
    println(res.flatten)
    

    【讨论】:

    • 谢谢大家的回答!我关于我的解决方案的问题:现在我只是打印这些列表。如何保存它们以便我可以引用它们并将它们组合起来?
    【解决方案2】:

    仅使用地图和展平的产品列表

    val nums = List(1, 2, 3)
    val chars = List('a', 'b')
    
    nums.map { a => chars.map { b => (a, b) } }.flatten
    

    Scala REPL

    scala> nums.map(a => chars.map(b => (a, b)))
    res5: List[List[(Int, Char)]] = List(List((1, 'a'), (1, 'b')), List((2, 'a'), (2, 'b')), List((3, 'a'), (3, 'b')))
    scala> nums.map(a => chars.map(b => (a, b))).flatten
    res6: List[(Int, Char)] = List((1, 'a'), (1, 'b'), (2, 'a'), (2, 'b'), (3, 'a'), (3, 'b'))
    

    可以使用flatMap和地图组合构建产品列表

    nums.flatMap { a => chars.map { b => (a, b) }} 
    

    产品列表也可以使用 for comprehension 构建

    for {a <- nums; b <- chars} yield (a, b)
    

    Scala REPL

    scala> val nums = List(1, 2, 3)
    val nums: List[Int] = List(1, 2, 3)
    
    scala> val chars = List('a', 'b')
    chars: List[Char] = List('a', 'b')
    
    scala> nums.flatMap { a => chars.map { b => (a, b) }}
    res2: List[(Int, Char)] = List((1, 'a'), (1, 'b'), (2, 'a'), (2, 'b'), (3, 'a'), (3, 'b'))
    
    scala> for {a <- nums; b <- chars} yield (a, b)
    res3: List[(Int, Char)] = List((1, 'a'), (1, 'b'), (2, 'a'), (2, 'b'), (3, 'a'), (3, 'b'))
    

    【讨论】:

    • 谢谢!这很棒
    【解决方案3】:
    val ls1 = List(1,2,3) 
    val ls2 = List('a','b') 
    def product[A](xs: List[A], ys: List[A])= xs.map(x => ys.map((x,_))).flatten 
    
    product(ls1,ls2) 
    

    【讨论】:

    • 谢谢!这完美地工作。 ys.map(x, _) 有什么作用?我认为该地图的语法为 ys.map (y=> some_manipulation_of_y)。为什么你只能说 ys.map(x, _ )?我认为它可能只是 ys.map (y => (x,_)) 的简写,但这给了我一些缺少的参数类型
    • 不客气。不确定您的意思,但是,基本上您从外部列表 (xs) 中获取表示为 x 的每个元素并将函数 ys.map((x,_)) 应用于它。 _ 只是 ys 元素的占位符。你也可以这样写:xs.map(x =&gt; ys.map(y =&gt; (x,y))).flatten