Scala中的复杂多维列表操作

Scala中的复杂多维列表操作,scala,slice,collect,Scala,Slice,Collect,给出如下列表: val dane = List( ("2011-01-04", -137.76), ("2011-01-04", 2376.45), ("2011-01-04", -1.70), ("2011-01-04", -1.70), ("2011-01-04", -1.00), // ... skip a few ... ("2011-12-22", -178.02), ("2011-12-29", 1800.82),

给出如下列表:

val dane = List(
    ("2011-01-04", -137.76),
    ("2011-01-04", 2376.45),
    ("2011-01-04", -1.70),
    ("2011-01-04", -1.70),
    ("2011-01-04", -1.00),
    // ... skip a few ...
    ("2011-12-22", -178.02),
    ("2011-12-29", 1800.82),
    ("2011-12-23", -83.97),
    ("2011-12-24", -200.00),
    ("2011-12-24", -30.55),
    ("2011-12-30", 728.00)
)
我希望按照指定顺序使用以下操作对特定月份(例如一月或
01
)的值(即内部列表的第二项)求和:

  • groupBy
  • slice
  • 收集
  • sum

  • 我觉得正好相反,所以这里的答案没有使用任何规定的方法:
    groupBy
    slice
    collect
    sum

    避免收集是最难的部分,
    condOpt
    /
    flatte
    更难看

    val YMD = """(\d\d\d\d)-(\d\d)-(\d\d)""".r
    
    import PartialFunction._
    
    (dane map {
      condOpt(_:(String,Double)){ case (YMD(_,"01",_), v) => v }  
    }).flatten reduceLeft {_+_}
    

    将问题分解为更小的步骤。首先,尝试每月将列表拆分为一个列表。您可以为此使用
    groupBy
    。您的第一个问题可能是如何解析日期字符串。一般的解决方案是使用自定义日期类和正则表达式;然而,在这种情况下,使用索引子字符串(或
    切片
    )的更简单的即席解决方案可能是合适的


    一般的技巧是将数据加载到scalarepl中并使用它。祝你好运。

    既然凯文已经开始了相反答案的趋势,这里有一个你永远不应该使用的答案,但是天哪,它奏效了!(并且避免了每个请求的方法,如果您更改字符串,它将在任何月份工作,但它确实要求列表按日期排序。)

    导入scala.collection.mutable.HashMap
    val totals=新哈希映射[Int,Double]
    
    对于(e我拒绝混淆
    sum

    import org.joda.time.DateMidnight
    for (month <- 1 to 12) yield {
      dane map { case (d,v) => new DateMidnight(d).getMonthOfYear -> v }
      filter { case (m, v) => m == month }
      map (_._2)
      sum
    }
    
    import org.joda.time.DateMidnight
    月份新日期午夜(d)。getMonthOfYear->v}
    过滤器{case(m,v)=>m==month}
    地图(图2)
    总和
    }
    
    (对于((YearMonthDay(u,1,u),value)因此,这里有一个想法:

    • groupBy
      ,因为您需要将每个月的数据分组在一起
    • 切片
      ,因为您需要查看哪一个是日期的月份
    • 收集
      ,因为您需要按月过滤
    ,并将
    映射到值
  • sum
    ,嗯……我不知道这是从哪里来的。有什么想法吗
  • 我真的应该查找“collect”,它应该以某种方式取代我的map/flatte/map



    我的结果是:Double=2234.29

    这不应该有“家庭作业”标签吗?最好的解决方案是不要按照您指定的顺序使用精确的操作;这样使用这些操作的唯一原因是作为家庭作业练习。“按此顺序使用groupBy、slice、collect、sum”…似乎有点限制性;那么现在谁在Scala布置家庭作业呢?@Rex以大约1秒的优势击败了我:)什么是/都是“whay中的monthy”?你是想说你需要在一月份列出所有的值以及它们的总和吗?@Rex这不是一个坏的理由,也许我会稍微咬一下衬里…现在这真是一件美妙的事情…它当然得到了我的支持!哈哈,好吧,如果它在/(如果它们有一个愚蠢的标签)上,我会投“-1,愚蠢的”一票。为什么
    dropWhile
    /
    takeWhile
    而不是简单的
    filter
    ?@Daniel-当然,filter也可以工作。我已经决定,如果有多个块,我想要第一个块,但没有理由选择它。我也没有努力编写最佳解决方案!你正在危险地接近有效的answ呃:)我卑躬屈膝地寻求你的原谅:-我在REPL中工作过,除非我在副本中遗漏了什么/paste@Debilski不,我没有,对我来说似乎很好。你到底观察到了什么错误?使用
    toMap
    你在一天内失去了所有的值,但最后一天除外。哈!你是对的……我应该发现这一点,我甚至在一年中故意使用它过去:)+1给你,先生,答案相应更新。我喜欢使用condOpt。我必须将它添加到我的曲目中。+1使用jodatime,是迄今为止处理日期的最好方式。我认为这是一种方便的方法。是的,这是我大多数项目中都会用到的东西,但不同的是,它不会成为一个好的图书馆在
    YearMonthDay
    上花费了太多时间。尝试
    val YearMonthDay=“”(\d+)(\d+)(\d+)”.r
    并在映射中使用
    “01”
    而不是
    1
    。不错,但您应该将
    映射到Int
    而不是应用三次。应该是
    def unapply(dateString:String):选项[(Int,Int,Int)]={
    ,不是吗(带括号的选项,而不是括号)。
    import scala.collection.mutable.HashMap
    val totals = new HashMap[Int, Double]
    for (e <- dane) {
        val (date, value) = e
        val month = date.drop(5).take(2).toInt
        totals(month) = totals.getOrElse(month,0.0) + value
    }
    
    import org.joda.time.DateMidnight
    for (month <- 1 to 12) yield {
      dane map { case (d,v) => new DateMidnight(d).getMonthOfYear -> v }
      filter { case (m, v) => m == month }
      map (_._2)
      sum
    }
    
    (for((YearMonthDay(_, 1, _), value)<-dane) yield value).sum
    
    object YearMonthDay{
       def unapply(dateString:String):Option((Int, Int, Int)) ={ 
           //yes, there should really be some error checking in this extractor 
           //to return None for a bad date string
           val components = dateString.split("-")
           Some((components(0).toInt, components(1).toInt, components(2).toInt)) 
      }  
    
    }
    
    dane.groupBy (_._1.matches (".*-01-.*")).slice (0, 1).map (x => x._2).flatten .map (y => y._2).sum