【问题标题】:In Scala what's a functional way to check that an array is monotonic?在 Scala 中,检查数组是否单调的功能性方法是什么?
【发布时间】:2016-09-06 06:28:26
【问题描述】:

我有一个数组val x : Array[Double],并且想检查一个函数的前提条件,即每个x(i) <= x(i+1) 对所有i。在 Scala 中使用函数式编程的方法是什么。我找了例如foldLeftfoldRight 但它们会累积而不是访问每一对相邻元素。

【问题讨论】:

  • 在 Haskell 中,你会 zip 一个包含自身的列表,以便获得成对的相邻元素。不确定它在 Scala 中是否同样优雅。
  • 为什么内部带有while循环的普通旧“def isMonotonic(...)”是“不雅”的?一个人不必使用那些低效的拉链/滑动来“发挥作用”。只要你的函数是纯的,就可以了。实用性应该是目标,而不是“优雅”。
  • OK 去掉了优雅的词 .. 我对函数式表单解决方案很感兴趣。功能对我来说很优雅的原因也许是个人的事情,但我想与更好的意图交流有关 = 优雅
  • @Bergi (vs, vs.view.drop(1)).zipped.forall(_ < _)。视图只管理索引,zipped 不构建任何东西。

标签: scala


【解决方案1】:

考虑一下:

def isMonotonic(arr:Array[Int]) = 
   if (arr.isEmpty) true
   else (arr, arr.tail).zipped.forall {case (a,b) => a <= b}

简化的解决方案(感谢@som-snytt):

def isMonotonic(arr:Array[Int]) = 
   (arr, arr.drop(1)).zipped.forall (_ <= _)

【讨论】:

  • 避免中间集合:(vs, vs.view.drop(1)).zipped.forall(_ &lt; _).
  • vs.view.drop(1) 是否等同于 vs.view.tail?我更喜欢第二个
  • 然后解决方案变得更加简单,感谢@som-snytt!
【解决方案2】:

你可以使用IterableLike.sliding:

val isMonotonic = 
  Seq(1,2,3,4,5).sliding(2).forall {
    case Seq(x, y) => x < y
    case _ => true
  }

编辑:

由于您使用的是Array[Double],因此您需要:

val isMonotonic = 
  Array(1d, 2d, 3d, 4d, 5d).sliding(2).forall {
    case Array(x, y) => x < y
    case _ => true
  }

【讨论】:

  • 也许是case x::y::_?
  • @Bergi 绝对优雅得多。
  • ::_ ?怎么会这样?
  • @jwvh 如果它存在,它只会忽略列表的尾部,不是吗?我看到它在 REPL 中工作。
  • 但这是我的问题。怎么会有尾巴?哪有什么可以忽略的?
【解决方案3】:

有几个很好的答案可供选择,下一个问题是:我们可以让它通用吗?

这是我的尝试。

def isMonotonic[T](ts: Traversable[T])(implicit ev: Ordering[T]): Boolean = {
  if (ts.size < 2) true
  else if (ev.gt(ts.head, ts.tail.head)) false
  else isMonotonic(ts.tail)
}

似乎适用于以下情况。

isMonotonic(Array('c','a','z'))             // false
isMonotonic(Vector(3.1, 2.2, 7.7))          // false
isMonotonic(List[Int]())                    // true
isMonotonic(Seq("abc", "bcb", "tz", "xs"))  // true

【讨论】:

    【解决方案4】:

    稍微不同的方法

    def isMonotonic(xs:List[Int]) = xs.sliding(2)
                                      .collectFirst{case List(x,y) if x > y => 1}
                                      .isEmpty
    

    适用于空列表和长度为一的列表,因为部分函数从未在这些列表上定义。因为它是collectFirst,所以它首先证明它不是单调的。如果愿意,可以使用xs zip xs.drop(1) 的想法

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-13
      • 2010-11-15
      • 2011-10-28
      • 2012-04-02
      • 2020-01-31
      相关资源
      最近更新 更多