Scala访问列表对象并评估周期数

时间:2016-09-03 14:28:54

标签: list scala apache-spark

Scala访问列表对象并评估周期数

我有对象列表

case class ItemDesc(a: Int, b: Int, c: Int, d: Int,e: Int, f: Int, g: Int desc: String)


val example = List(ItemDesc(6164,6165,6166,-6195,-6175,-6186,-6195, The values are correct), ItemDesc(14879,-14879,14879,-14894, 14879,14879,14894, The values are ok), ItemDesc(19682,-19690,-19682,19694,19690,19682,19694,The values are good),ItemDesc(5164,-5165,-5166,-6195,5165,5166,6195,The values are correct),ItemDesc(5879,5879,5879,5894,5879,5879,5879,The values are ok))

从'example'列表中,我想访问对象'ItemDesc'。并获得周期数。它从负数转为正数并且在> = 2秒内保持正数。

如果> = 2秒,那就是一个周期。

示例1 :( 6164,6165,6166,-6195,-6175,-6186,-6195,不错)

没有。周期为2。

原因:当我们从列表的第一个元素移动到第三个元素时,我们有2个间隔,这意味着2秒。间隔是> = 2.所以它是一个循环。当我们向列表的第3个元素移动到第4个元素时,它是负值。所以我们从第4个元素开始计数并移动到第7个元素,所有元素都有相同的负号。我们有3个间隔,这意味着3秒。间隔是> = 2.所以它是一个循环。我们开始计算从零开始的间隔,因为一个数字从正变为负,反之亦然。

示例2 :( 14879,-14879,14879,-14894,14879,14879,14894,更好)

没有。周期为1。

原因:当我们从列表的第一个元素移动到第二个元素时,符号变为负数。所以我们从零开始计算间隔。从元素2到3,符号变为负数。所以间隔计数器为零。从元素3到4,符号变为负数。间隔计数器为零。从第5到第7,所有值都有相同的符号,我们有2个间隔,这意味着2秒。区间是> = 2.所以它是一个周期。

示例3 :(5164,-5165,-5166,-6195,5165,5166,6195,不错)

没有。周期为2

我写的下面的代码并没有给我这个号码。我正在寻找的周期。感谢帮助修复它。

object findCycles {
def main(args: Array[String]) {

var numberOfPositiveCycles = 0
var numberOfNegativeCycles = 0
var numberOfCycles = 0

case class itemDesc(a: Int, b: Int, c: Int, d: Int, reason: String)

val example = List(ItemDesc(6164,6165,6166,-6195,-6175,-6186,-6195, The values are correct), ItemDesc(14879,-14879,14879,-14894, 14879,14879,14894, The values are ok), ItemDesc(19682,-19690,-19682,19694,19690,19682,19694,The values are good),ItemDesc(5164,-5165,-5166,-6195,5165,5166,6195,The values are correct),ItemDesc(5879,5879,5879,5894,5879,5879,5879,The values are ok))    

val data2 = example.map(x => getInteger(x)).filter(_ != "unknown").map(_.toString.toInt)
//println(data2)

     var nCycle = findNCycle(data2)
     println(nCycle)
   }

    def getInteger(obj: Any) = obj match {
    case n: Int => obj
    case _     => "unknown"
    }

   def findNCycle(obj: List[Int]) : Int = {      

    def NegativeCycles(fit: itemDesc): Int = {
    if (fit.a < 0 && fit.b < 0 && fit.c < 0) || if( fit.b < 0 && fit.c < 0 && fit.d < 0)
    {
      numberOfNegativeCycles += 1
    }
    }
    //println("negative cycle="+cycles)
    def PositiveCycles(fit: itemDesc): Int = {
      if (fit.a > 0 && fit.b > 0 && fit.c > 0) || if( fit.b > 0 && fit.c > 0 && fit.d > 0)
      {
        numberOfPositiveCycles += 1
      }
    }
    //println("positive cycle="+cycles)

    numberOfCycles = numberOfPositiveCycles + numberOfNegativeCycles
    return numberOfCycles 

  }

}

有关逻辑的参考,您可以参考 - Number of Cycles from list of values, which are mix of positives and negatives in Spark and Scala

4 个答案:

答案 0 :(得分:0)

好的,这很粗糙,但我认为它可以满足您的需求。我确信有更优雅的方法来进行拆分方法。

我没有使用你的ItemDesc,因为你给出的例子给出的问题更简单。

object CountCycles extends App {

  // No. of cycles is 1.
  val example1 = List(1, 2, 3, 4, 5, 6, -15, -66)

  // No. of cycles is 3.
  val example2 = List(11, 22, 33, -25, -36, -43, 20, 25, 28)

  // No. of cycles is 8
  val example3 = List(1, 4, 82, 5, 6, -2, -12, -22, -32, 100, 102, 100, 102, 0, 0, -2, -12, -22, -32, 4, 82, 5, 6, -6, 8, -6, -6, 8, 8, -5, -6, -7, 9, 8, 6, -5, -6, -7)

  def differentSign(x: Int, y: Int): Boolean =
    (x < 0) != ( y < 0)

  // return a list of sections
  def split(l: List[Int]): List[List[Int]] =
    l match {
      case Nil ⇒ Nil
      case h :: _ ⇒
        val transition: Int = l.indexWhere(differentSign(h, _))
        if (transition < 0) List(l)
        else {
          val (head, tail) = l.splitAt(transition)
          head :: split(tail)
        }
    }

  def count(l: List[Int]): Int = {
    val pos: List[List[Int]] = split(l)
    // count is the number of sections of length > 2
    pos.count(_.length > 2)
  }

  println(count(example1)) // 1
  println(count(example2)) // 3
  println(count(example3)) // 8
}

答案 1 :(得分:0)

对于您在示例中有7个项目的情况,这应该是一个有效的解决方案,如说明中所示。如果你的case类改变了,而是有一个值列表,那么隐式助手可以用对访问者的简单调用替换

import scala.annotation.tailrec
import scala.language.implicitConversions

object CyclesCounter extends App {

  val examples = List(
    ItemDesc(6164,6165,6166,-6195,-6175,-6186,-6195, "The values are correct"),
    ItemDesc(14879,-14879,14879,-14894, 14879,14879,14894, "The values are ok"),
    ItemDesc(19682,-19690,-19682,19694,19690,19682,19694,"The values are good"),
    ItemDesc(5164,-5165,-5166,-6195,5165,5166,6195,"The values are correct"),
    ItemDesc(5879,5879,5879,5894,5879,5879,5879,"The values are ok"))

  val counter = new CycleCounter

  // Add the index for more readable output
  examples.zipWithIndex.foreach{ case (item, index) => println(s"Item at index $index has ${counter.cycleCount(item)} cycles")}
}

class CycleCounter {

  def cycleCount(item: ItemDesc): Int = {

  @tailrec
  def countCycles(remainingValues: List[Int], cycles: Int): Int = {
    if (remainingValues.isEmpty) cycles
    else {
      val headItems = {
        if (remainingValues.head < 0) remainingValues.takeWhile(_ < 0) 
        else remainingValues.takeWhile(_ >= 0)
      }

      val rest = remainingValues.drop(headItems.length)

      if (headItems.length > 2) countCycles(rest, cycles + 1) else countCycles(rest, cycles )
    }
  }

  countCycles(item, 0)
}

// Helper to convert ItemDesc into a List[Int] for easier processing
implicit def itemToValueList(item: ItemDesc): List[Int] = List(item.a, item.b, item.c, item.d, item.e, item.f, item.g)

}

case class ItemDesc(a: Int, b: Int, c: Int, d: Int, e: Int, f: Int, g: Int, reason: String)

跑步输出:

Item at index 0 has 2 cycles
Item at index 1 has 1 cycles
Item at index 2 has 1 cycles
Item at index 3 has 2 cycles
Item at index 4 has 1 cycles

希望有所帮助

答案 2 :(得分:0)

正如我所读到的,我看到你的问题是将案例类视为单个实体而不是元素列表和原因。我会将case类更改为其中一个替代,首先是元素的数量是静态的(在这种情况下为4):

case class ItemDesc(a: Int, b: Int, c: Int, d: Int, reason: String) {
    lazy val getAsList = List(a,b,c,d)
  }

ItemDesc(1,2,3,4,"reason").getAsList

在第二种情况下,如果元素的数量是无界的,则可以使用它:

case class ItemDescAlt(reason:String, elements: Int*)

ItemDescAlt("reason", 5164,-5165,-5166,-6195,5165,5166,6195)

和其他人一样,我会提供自定义版本来计算周期数:

def getCycles(list: Seq[Int]): Int = {
    def headPositive(list: Seq[Int]): Boolean = {
      list.headOption.forall(_ >= 0)
    }
    val result = list.foldLeft((0, 0, !headPositive(list))) { //we start with a symbol diferent to the firs one
      case ((numberOfCycles, cycleLength, lastWasPositive), number) => { //for each element...
        val numberSign = number >= 0
        val actualCycleLength = if (numberSign == lastWasPositive) { //see if the actual simbol is equal to the last one
          cycleLength + 1 //in that case the length is increased
        } else {
          0 //in the other reset it
        }
        val actualNCycles = if (actualCycleLength == 2) { //if the actual length is equal to to
          numberOfCycles + 1 //it is a proper new cycle
        } else {
          numberOfCycles // no new cycles
        }
        (actualNCycles, actualCycleLength, numberSign) //return the actual state
      }
    }
    result._1 //get the final number of cycles
  }

答案 3 :(得分:0)

如果您已经有List的解决方案,则可以使用productIterator将任何案例类转换为列表:

scala> case class X(a:Int, b:Int, c:String)
defined class X

scala> val x = X(1,2,"a")
x: X = X(1,2,a)

scala> x.productIterator.toList
res1: List[Any] = List(1, 2, a)

主要问题是您返回List[Any],因此您可能需要做更多工作才能获得List[Int]