Как я могу накапливать свои итоги более функциональным способом? - PullRequest
3 голосов
/ 17 ноября 2011

На данный момент у меня есть

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 ]

6 голосов
/ 17 ноября 2011

Поскольку 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)
4 голосов
/ 17 ноября 2011

Это должно работать:

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
    }
}
3 голосов
/ 17 ноября 2011

Для справки, вот решение с использованием метода 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
3 голосов
/ 17 ноября 2011

Я думаю, вы делаете это неправильно. Не создавайте Map напрямую: создайте последовательность. В этом случае ListBuffer, вероятно, является наиболее подходящим, так что вы можете легко добавлять элементы к нему. Он также поддерживает постоянное время toList, хотя это не должно иметь значения.

Если вам нужен функциональный подход, вы можете либо добавить к List и reverse это, либо пойти по пути повторений . Мне не совсем удобно с последним объяснять их.

Как только вы получите свою коллекцию, вы ее 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 опускает семя. Я мог бы избежать необходимости делать это, используя tail и head, но для этого потребовалась бы проверка, чтобы определить, является ли accum пустым.

var можно удалить, используя итерации, или, возможно, используя монаду состояния на более высоком уровне.

0 голосов
/ 17 ноября 2011
var sum = 0
orders.toList.sortBy (-_._1).map (o =>
  {sum += o._2; (o._1 -> sum) }).toMap 

Не очень элегантно, так как использует вар.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...