【问题标题】:Retrieving Values from a Seq based on a condition根据条件从 Seq 中检索值
【发布时间】:2020-10-24 02:03:32
【问题描述】:

我有以下序列

scala>   var al = Seq((1.0, 20.0, 100.0), (2.0, 30.0, 100.0), (1.0, 11.0, 100.0), (1.0, 20.0, 100.0), (1.0, 10.0, 100.0),(2.0,9.0,100.0))
al: Seq[(Double, Double, Double)] = List((1.0,20.0,100.0), (2.0,30.0,100.0), (1.0,11.0,100.0), (1.0,20.0,100.0), (1.0,10.0,100.0), (2.0,9.0,100.0))

如何从这个 Seq 中获取前 n 个元素,其中 - 第二项的总和大于第三项的 60%(这将是一个常数值)

预期输出 -

scala> Seq((1.0, 20.0, 100.0), (2.0, 30.0, 100.0), (1.0, 11.0, 100.0))
res30: Seq[(Double, Double, Double)] = List((1.0,20.0,100.0), (2.0,30.0,100.0), (1.0,11.0,100.0))

编辑 -1

我用一些丑陋的方式做到了这一点。但是,如果有任何漂亮的功能性方法来解决这个问题,那就太好了。我真的需要摆脱这个计数器,对我来说有点棘手。

var counter =0d ; var sum = 0d 
var abc :Seq[Double] = for (x <- al) yield {
counter+=1 ;sum = sum + x._2 ; 
if (sum > 60) counter else 0
} 
println(al.take(abc.filterNot(_==0).min.toInt))

【问题讨论】:

  • 你试过什么?什么不起作用?
  • 查看takeWhile 方法:scala-lang.org/api/2.12.3/scala/collection/Seq.html 它可以根据需要工作
  • @Jean-PhilippePellet ,我在学习解决问题的实用方法时尝试了一些丑陋的东西。这个 >>> var counter =0d ; var sum = 0d var abc :Seq[Double] = for (x 60) counter else 0} println(al.take(abc.filterNot(_==0).min.toInt))
  • @Boris。我正在尝试我上面提到的东西。但我没有正确连接。

标签: arrays scala arraylist seq take


【解决方案1】:

您可以使用带有累加器的递归函数来获取所需数量的元素:

def getIndex(input: Seq[(Double,Double,Double)], index: Int = 0, sum: Double = 0.0): Int = {
    input match {
    case Seq() => index
    case Seq(head, _@_*) if head._2 + sum > head._3 * 0.6 => index + 1  
    case Seq(head, tail@_*) => getIndex(tail, index + 1, sum + head._2)
  }
}

al.take(getIndex(al))

或者建立一个列表:

def getList(input: Seq[(Double,Double,Double)], sum: Double = 0.0): List[(Double,Double,Double)] = {
    input match {
    case Seq() => List.empty
    case Seq(head, _@_*) if head._2 + sum > head._3 * 0.6 => head :: List.empty
    case Seq(head, tail@_*) => head :: get(tail, sum + head._2)
  }
}

getList(al)

如 cmets 中所述 - 将 al 限制为 List 可以允许使用 ::,这应该更有效:

def get(input: List[(Double,Double,Double)], sum: Double = 0.0): List[(Double,Double,Double)] = {
    input match {
    case Seq() => List.empty
    case head :: tail if head._2 + sum > head._3 * 0.6 => head :: List.empty
    case head :: tail => head :: get(tail,  sum + head._2)
  }
 }

【讨论】:

  • @LuisMiguelMejíaSuárez 谢谢,请检查一下现在好些了吗?
  • 是的,至少它有效。它可能效率极低,但是无论如何处理通用海洋从来都没有意义。我只想要求一个列表
  • @abc_spark 很乐意提供帮助!
【解决方案2】:

如果您使用的是 Scala 2.13.x,那么您可能会 unfold():

Seq.unfold((al,0.0)){ case (lst,sum) =>
  Option.when(lst.nonEmpty && sum < 0.6 * lst.head._3) {
    (lst.head, (lst.tail, sum + lst.head._2))
  }
}
//res0: Seq[(Double, Double, Double)] =
// List((1.0,20.0,100.0), (2.0,30.0,100.0), (1.0,11.0,100.0))

在早期的 Scala 版本中,您可以 scanLeft() 计算总和并使用它来计算 take() 有多少元素。

val cnt = al.view
            .scanLeft(0.0)(_ + _._2)
            .takeWhile(_ < 0.6 * al.headOption.getOrElse((0d,0d,0d))._3)
            .length
al.take(cnt)

【讨论】:

  • 感谢您的回答:)
猜你喜欢
  • 2014-06-19
  • 1970-01-01
  • 1970-01-01
  • 2022-01-16
  • 1970-01-01
  • 1970-01-01
  • 2014-04-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多