【问题标题】:Scala - can a lambda parameter match a tuple?Scala - lambda参数可以匹配元组吗?
【发布时间】:2011-11-02 01:59:15
【问题描述】:

所以说我有一些类似的列表

val l = List((1, "blue"), (5, "red"), (2, "green"))

然后我想过滤掉其中一个,我可以做类似的事情

val m = l.filter(item => {
    val (n, s) = item          // "unpack" the tuple here
    n != 2
}

有什么方法可以直接将元组“解包”为 lambda 的参数,而不是使用这个中间 item 变量?

类似下面的东西是理想的,但 eclipse 告诉我 wrong number of parameters; expected=1

val m = l.filter( (n, s) => n != 2 )

任何帮助将不胜感激 - 使用 2.9.0.1

【问题讨论】:

    标签: scala


    【解决方案1】:

    这是你能得到的最接近的:

     val m = l.filter { case (n, s) => n != 2 }
    

    它基本上是匿名PartialFunction 中的模式匹配语法。 Function 对象和特征中也有 tupled 方法,但它们只是此模式匹配表达式的包装。

    【讨论】:

    • 您可以将s 替换为_,因为它从未使用过。
    【解决方案2】:

    嗯,虽然 Kipton 有一个很好的答案。您实际上可以通过这样做来缩短它。

    val l = List((1, "blue"), (5, "red"), (2, "green"))
    val m = l.filter(_._1 != 2)
    

    【讨论】:

    • 更短并不能让它变得更好。这对于非常琐碎的示例是有意义的,但对于更复杂的东西,Kipton 的示例将导致代码更具可读性。
    • 我对此(5 年后)投了反对票,因为它实际上并没有回答我的问题。我的问题是如何解包元组,而不是如何过滤列表。
    • 我认为这里有两个答案是有帮助的。我认为这种方法更适合简单的情况。即使它没有回答实际问题,登陆这里的人也可能不知道这一点。而接受的答案当然直接回答了这个问题。
    【解决方案3】:

    有很多选择:

    for (x <- l; (n,s) = x if (n != 2)) yield x
    l.collect{ case x @ (n,s) if (n != 2) => x }
    l.filter{ case (n,s) => n != 2 }
    l.unzip.zipped.map((n,s) => n != 2).zip   // Complains that zip is deprecated
    

    【讨论】:

      【解决方案4】:
      val m = l.filter( (n, s) => n != 2 )
      

      ... 是类型不匹配,因为 lambda 定义了一个

      • Function2[String,Int,Boolean] 有两个参数而不是
      • Function1[(String,Int),Boolean] 一个 Tuple2[String,Int] 作为其参数。

      您可以像这样在它们之间进行转换:

      val m = l.filter( ((n, s) => n != 2).tupled )
      

      【讨论】:

        【解决方案5】:

        我也有同样的想法,今天来回答你的问题。

        我不太喜欢偏函数方法(任何具有case 的方法),因为它们暗示逻辑流可能有更多入口点。至少对我来说,它们往往会模糊代码的意图。另一方面,我真的很想像你一样直接进入元组字段。

        这是我今天起草的解决方案。它似乎有效,但我还没有在生产中尝试过。

        object unTuple {
          def apply[A, B, X](f: (A, B) => X): (Tuple2[A, B] => X) = {
            (t: Tuple2[A, B]) => f(t._1, t._2)
          }
          def apply[A, B, C, X](f: (A, B, C) => X): (Tuple3[A, B, C] => X) = {
            (t: Tuple3[A, B, C]) => f(t._1, t._2, t._3)
          }
          //...
        }
        
        val list = List( ("a",1), ("b",2) )
        val list2 = List( ("a",1,true), ("b",2,false) )
        
        list foreach unTuple( (k: String, v: Int) =>
          println(k, v)
        )
        
        list2 foreach unTuple( (k: String, v: Int, b: Boolean) =>
          println(k, v, b)
        )
        

        输出:

        (a,1)
        (b,2)
        (a,1,true)
        (b,2,false)
        

        也许这很有用。 unTuple 对象自然应该放在某个工具命名空间中。

        附录:

        适用于您的案例:

        val m = l.filter( unTuple( (n:Int,color:String) =>
            n != 2
        ))
        

        【讨论】:

          猜你喜欢
          • 2010-11-23
          • 1970-01-01
          • 2014-02-05
          • 2023-03-07
          • 2020-08-21
          • 2012-08-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多