【问题标题】:Seq with maximal elements具有最大元素的序列
【发布时间】:2012-11-12 17:30:29
【问题描述】:

我有一个 Seq 和函数 Int => Int。我需要实现的是从原始 Seq 中只取那些等于结果序列最大值的元素(那个,我将在应用给定函数后得到):

def mapper:Int=>Int= x=>x*x
val s= Seq( -2,-2,2,2 )
val themax= s.map(mapper).max
s.filter( mapper(_)==themax)

但这似乎很浪费,因为它必须映射两次(一次用于过滤器,另一次用于最大值)。 有一个更好的方法吗? (希望不使用循环)

编辑 该代码已被编辑;原来这是过滤器行:s.filter( mapper(_)==s.map(mapper).max)。正如om-nom-nom 所指出的,这会评估 `s.map(mapper).max 每次(过滤器)迭代,导致二次复杂度。

【问题讨论】:

  • 目前尚不清楚您在上面究竟想做什么。
  • 有一件事情比双遍历更浪费:你在 s.map(mapper) 上调用 max 而 max 是 O(n)。所以你最终会得到二次复杂度。
  • @om-nom-nom 是的,我想知道这一点,所以我不久前进行了编辑。我会把最大值放在一个 val 中
  • @Jatin 这是高度简化的代码,因为我正在处理原始的复杂结构;我不确定如何进一步简化它。如果它使这一点更清楚,在原始这不是 Int 的 Seq,而是对象的 Seq。我想要做的就是获取最大元素(在应用该函数之后)。
  • @scala_newbie 现在很清楚:)。我问的是前面的代码,你在过滤器中有最大值。

标签: scala mapping


【解决方案1】:

这是一个只进行一次映射并使用 `foldLeft' 函数的解决方案:

原则是遍历seq,对于每个映射元素,如果它大于之前映射的所有元素,则开始一个新的序列,否则返回所有最大值的列表和新的映射最大值。最后,如果小于则返回先前计算的最大值 Seq。

def getMaxElems1(s:Seq[Int])(mapper:Int=>Int):Seq[Int] = s.foldLeft(Seq[(Int,Int)]())((res, elem) => {
  val e2 = mapper(elem)
  if(res.isEmpty || e2>res.head._2) 
    Seq((elem,e2)) 
  else if (e2==res.head._2) 
    res++Seq((elem,e2)) 
  else res 
}).map(_._1) // keep only original elements

// test with your list
scala> getMaxElems1(s)(mapper)
res14: Seq[Int] = List(-2, -2, 2, 2)

//test with a list containing also non maximal elements
scala> getMaxElems1(Seq(-1, 2,0, -2, 1,-2))(mapper)
res15: Seq[Int] = List(2, -2, -2)

备注:关于复杂度

我上面介绍的算法对于具有 N 个元素的列表具有 O(N) 的复杂度。然而:

  • 映射所有元素的操作复杂度为 O(N)
  • 计算最大值的操作复杂度为 O(N)
  • 压缩操作的复杂度为 O(N)
  • 根据最大值过滤列表的操作也是复杂度O(N)
  • 映射所有元素的操作复杂度为 O(M),其中 M 是最终元素的数量

所以,最后您在问题中提出的算法与我的答案具有相同的复杂性(质量),而且您提出的解决方案比我的更清楚。因此,即使“foldLeft”功能更强大,对于此操作,我也会推荐您的想法,但压缩原始列表并仅计算一次地图(特别是如果您的地图比简单的正方形更复杂)。这是在 question/chat/cmets 中借助 *scala_newbie* 计算的解决方案。

def getMaxElems2(s:Seq[Int])(mapper:Int=>Int):Seq[Int] = {
  val mappedS = s.map(mapper) //map done only once 
  val m = mappedS.max         // find the max
  s.zip(mappedS).filter(_._2==themax).unzip._1
}

// test with your list
scala> getMaxElems2(s)(mapper)
res16: Seq[Int] = List(-2, -2, 2, 2)

//test with a list containing also non maximal elements
scala> getMaxElems2(Seq(-1, 2,0, -2, 1,-2))(mapper)
res17: Seq[Int] = List(2, -2, -2)

【讨论】:

  • 这很聪明:O。请注意,我正在尝试获取 original 元素,而不是映射的元素,但我想可以将原始元素保留在该 Seq 中并在单独的参数中返回最大值,对吧?
  • 查看编辑后的代码,我仍然更喜欢第二种解决方案,即使它现在往往比第一种更复杂。
  • 另外,关于复杂性,幸运的是我的地图是 O(1)。我最初的想法是映射一次,获取最大值,然后获取条件评估为 True 的 indexes,并仅获取这些索引上的元素(这就是你在 MATLAB 中的做法,或 python-numpy),但我找不到一个方法(我想有人可以写一个 for...)
  • 在函数式编程中,zip 通常比索引更受欢迎。
  • 我对 scala 的了解不够,无法让第二个解决方案返回原始元素而不是映射的元素。关于zip,确实,我想用映射的元素压缩原始元素会更好!
猜你喜欢
  • 2013-09-28
  • 2019-04-08
  • 1970-01-01
  • 1970-01-01
  • 2011-08-28
  • 1970-01-01
  • 1970-01-01
  • 2014-07-17
  • 1970-01-01
相关资源
最近更新 更多