【问题标题】:Check if two adjoined elements are ordered using reduceLeft检查两个相邻元素是否使用 reduceLeft 排序
【发布时间】:2021-07-02 00:04:21
【问题描述】:

我有一个练习来检查两个相邻的元素是否使用 sliding,map,reduceLeft 进行排序。例如:

val seq1 = Seq(1,2,2,4)
isOrdered(seq1)(_ < _) == false
isOrdered(seq1)(_ <= _) == true


def isOrdered[A](seq: Seq[A])(leq: (A,A) => Boolean): Boolean = { 

}

老实说,我不知道从什么开始。

【问题讨论】:

  • 好的,我的第一个想法是使用滑动(2),所以我有 List(List(1,2), List(2,2), List(2,4)) 但如何现在比较一下?
  • 我也尝试过扁平化一个列表,所以我想要一个元组:List((1,2),(2,2),(2,4)) 使用:val seq= Seq(1,2,2,4) val seqSlided = seq.sliding(2).toSeq val seqTupled = seqSlided match { case List(a,b)::rest =&gt; (a,b)::rest }但我的结果是 List((1,2), List(2,2), List(2,4)) 所以它只适用于 List 中的第一个。

标签: scala functional-programming


【解决方案1】:

一种方法包括forall,其中leq: (A,A) =&gt; Boolean 必须适用于每个元素,

def isOrdered[A](seq: Seq[A])(leq: (A,A) => Boolean): Boolean = {
  seq.sliding(2).forall { case(Seq(l,r)) => leq(l,r) }
}

因此对于val seq1 = Seq(1,2,2,4)

scala> isOrdered(seq1)(_<_)
val res5: Boolean = false

scala> isOrdered(seq1)(_<=_)
val res6: Boolean = true

【讨论】:

    【解决方案2】:

    "使用滑动、映射、减少"

    def isOrdered[A](seq: Seq[A])(pred: (A,A) => Boolean): Boolean =
      seq.sliding(2)
         .map{case Seq(a,b) => pred(a,b)}
         .reduce(_ && _)
    

    注意:对于小于 2 个元素的序列不安全。

    【讨论】:

    • reduce()map() 操作中获取所有Boolean 结果并将它们简化为单个Boolean 结果。
    • 我知道,但我不知道它是如何工作的,例如(false, false, false) 当所有的 and 都为 false && false = true 时,那又如何?
    • reduce() 采用前 2 个元素并将它们组合起来(根据给定的操作)。然后它获取该结果并将其与下一个元素组合。这一直持续到它用完下一个元素来与上一个结果结合。
    【解决方案3】:

    以下是使用这三个操作的方法:

    def isOrdered[A](seq: Seq[A])(leq: (A, A) => Boolean): Boolean =
      seq
        .sliding(2)
        .map { case e1 :: e2 :: Nil => leq(e1, e2) }
        .reduceLeft(_ && _)
    

    首先,我们使用滑动将序列分成两个连续元素的组。然后我们在每一对上应用leq(换句话说,我们将每个二元素列表映射到这两个元素上leq 的结果)。最后,我们将布尔值的结果序列简化为具有逻辑 AND 的单个布尔值,这意味着我们的谓词需要为所有值保留。

    val seq1 = Seq(1, 2, 2, 4)
    
    val less: (Int, Int) => Boolean = _ < _
    val lessOrEqual: (Int, Int) => Boolean = _ <= _
    
    isOrdered(seq1)(less) // false
    isOrdered(seq1)(lessOrEqual) // true
    

    这里有一些不安全的问题:

    1. 如果您有一个单元素序列,则滑动操作将在单列表元素上生成一个迭代器,并且模式匹配将失败。
    2. 如果您有一个空序列,reduce 将会爆炸。

    【讨论】:

    • 我有点困惑 reduce 在那里的工作方式。假设:我们使用“less”,所以在第一次检查之后我们有 True,因为 1
    • () 与 {} 的最简单答案是我通常更喜欢 (),但我必须在这里使用 {},因为我有一个部分函数(使用 case)。这是 Scala 语法中我不喜欢的罕见事物之一,我希望我能更简单地解释一下。第二个问题更容易 - 因为列表的head :: tail 性质。对于e1 :: e2 :: Nil,模式匹配将列表识别为List(e1, e2, theRest)(theRest 为空列表),而对于e1 :: e2,它将被识别为List(e1, theRest)。我不会匹配前两个元素,而是匹配第一个元素和列表的其余部分。
    • .toList 添加到 你会自己看到它。在做sliding(2)之后,我们产生了一个列表列表,然后我们修改了外部列表的每个元素(通过映射),这意味着我们修改了每个内部的二元素列表。我们如何修改它?它的格式为 [e1, e2],因此我们对其进行模式匹配以提取这些元素并使用它们。请注意,在我们执行了sliding(2) 之后,我们知道每个内部列表都是一个二元素列表,因此我们使用e1 :: e2 :: Nil 进行匹配。如果我们说 e1 :: e2 :: 不管,它的工作原理是一样的,但前者更具体。
    • > 我不明白。不用担心,我认为这是一个更笼统的讨论,而不仅仅是对相邻元素进行排序 :) 我很乐意为您提供帮助并向您展示 Scala 中的工作原理,但是请让我们将讨论移到这种格式之外,因为没有这种格式真的很难工作正确的格式和有限的字符等
    • 给你写信了,不知道好不好
    猜你喜欢
    • 2019-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-29
    • 2014-07-29
    相关资源
    最近更新 更多