如何以更实用的方式累积我的总数?

时间:2011-11-16 23:46:15

标签: scala

目前我有

val orders = new HashMap[Int, Int]
orders.put(36, 110)
orders.put(35, 90)
orders.put(34, 80)
orders.put(33, 60)

我想继续运行,以便结束映射如下所示

36 -> 110
35 -> 200
34 -> 280
33 -> 340

目前我必须按照以下方式执行此操作

val keys = orders.keys.toList.sortBy(x => -x)
val accum = new HashMap[Int, Int]
accum.put(keys.head, orders(keys.head))
for (i <- 1 to keys.length - 1) {
  accum.put(keys(i), orders(keys(i)) + accum(keys(i-1)))
}
accum.foreach {
  x => println(x._1, x._2)
}

使用映射,折叠等方法有更多功能吗?我可以用一个直接的列表来完成它但是我不能完全理解如何用HashMap做这个

编辑:订购非常重要。左列(36,35,34,33)需要按降序排列

5 个答案:

答案 0 :(得分:6)

由于HashMaps没有排序,直接执行此操作并不是那么简单,因此首先转换为有序序列:

val elems = orders.toSeq.sortBy(-_._1)
             .scanLeft(0,0)((x, y) => (y._1, x._2 + y._2)).tail

  // ArrayBuffer((36,110), (35,200), (34,280), (33,340))

如果你真的想把它们放在一个反向排序的有序地图中,而不是只打印出来,你可以这样做:

val accum = collection.SortedMap(elems: _*)(
            new Ordering[Int] { def compare(x: Int, y: Int) = y compare x })

  // SortedMap[Int,Int] = Map(36 -> 110, 35 -> 200, 34 -> 280, 33 -> 340)

答案 1 :(得分:4)

这应该有效:

val orders = new HashMap[Int, Int]
orders.put(36, 110)
orders.put(35, 90)
orders.put(34, 80)
orders.put(33, 60)

val accum = new HashMap[Int, Int]

orders.toList.sortBy(-_._1).foldLeft(0){
    case (sum, (k, v)) => {
     accum.put(k, sum + v)
     sum + v
    }
}

答案 2 :(得分:3)

我认为你做错了。不要直接创建Map:创建序列。在这种情况下,ListBuffer可能是最合适的,因此您可以轻松地向其追加元素。它也支持恒定时间toList,但这在这里无关紧要。

如果您必须使用功能方法,则可以预先添加到Listreverse,或者采用 iteratees 的方式。不过,我对后者的解释不够舒服。

收藏后,您将scanLeft。或者,如果您构建了List,则可以scanRight而不是reverse。之后,只需在结果上调用toMap即可。

粗略地说:

var accum: List[(Int, Int)] = Nil
accum ::= 36 -> 110
accum ::= 35 -> 90
accum ::= 34 -> 80
accum ::= 33 -> 60

val orders = accum.scanRight(0 -> 0) {
  case ((k, v), (_, acc)) => (k, v + acc)
}.init.toMap

init掉落种子。我本可以避免使用tailhead来执行此操作,但这需要检查accum是否为空。

可以使用iteratees删除var,也可以使用更高级别的状态monad删除。{/ p>

答案 3 :(得分:3)

对于记录,这是使用inits方法的解决方案:

 import scala.collection.mutable._

 // use a LinkedHashMap to keep the order
 val orders = new LinkedHashMap[Int, Int]
 orders.put(36, 110)
 orders.put(35, 90)
 orders.put(34, 80)
 orders.put(33, 60)


// create a list of init sequences with no empty element
orders.toSeq.inits.toList.dropRight(1).

  // > this returns
  // ArrayBuffer((36,110), (35,90), (34,80), (33,60)) 
  // ArrayBuffer((36,110), (35,90), (34,80)) 
  // ArrayBuffer((36,110), (35,90)) 
  // ArrayBuffer((36,110)) 

  // now take the last key of each sequence and sum the values of the sequence
  map(init => (init.last._1, init.map(_._2).sum)).reverse.toMap.mkString("\n")

  36 -> 110
  35 -> 200
  34 -> 280
  33 -> 340

答案 4 :(得分:0)

var sum = 0
orders.toList.sortBy (-_._1).map (o =>
  {sum += o._2; (o._1 -> sum) }).toMap 

不是很优雅,因为它使用了var。