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
答案 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]