Скала, собери двойной футляр - PullRequest
1 голос
/ 23 января 2011

Привет. Как преобразовать это

<code></p>

<p>for (w <- m ){
    val w = (w._2.collect { 
        case x if (x._2 > 0) => x._2;
        case x if (x._2 < 0) => x._2 }) // if I add here .sum i got sum of (negative and positive) together
  }
, чтобы получить сумму положительных и отрицательных значений за один сбор, это может быть List (positive.sum, absolute.sum) или два значения

редактировать: только сгруппировать, нарезать, собирать, суммировать и давать

Я написал рабочую программу, но она не была принята, потому что она делает два сбора

<code>
val m = d.groupBy(_._1.slice(0, 7))
    for (w<- m) {
     val x = (w._2.collect { case x if (x._2>  0) =>  x._2 }).sum
     val y = (w._2.collect { case x if (x._2<  0) =>  x._2 }).sum
      println("%7s %11.2f %11.2f %11.2f" format(w._1 , x , y ,(x+y)))
    }
}<br>
входные данные
<code></p>

<p>
val d = 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),
    ("2011-01-06", 865.70),
    ("2011-01-07", -734.15),
    ("2011-01-05", -188.63),
    ("2011-01-06", -73.50),
    ("2011-01-07", -200.00),
    ("2011-01-09", -215.35),
    ("2011-01-09", -8.86),
    ("2011-01-09", -300.00),
    ("2011-01-11", -634.54),
    ("2011-01-11", -400.00),
    ("2011-01-12", -92.87),
    ("2011-01-13", -1839.24),
    ("2011-01-13", 10000.00),
    ("2011-01-13", -10000.00),
    ("2011-01-15", -127.97),
    ("2011-01-15", -319.02),
    ("2011-01-19", -549.00),
    ("2011-01-21", -164.80),
    ("2011-01-23", -500.00),
    ("2011-01-25", -377.97),
    ("2011-01-26", 2158.66),
    ("2011-01-26", -130.45),
    ("2011-01-27", -350.00),
    ("2011-01-29", -500.00),
    ("2011-02-01", 2376.45),
    ("2011-02-01", 955.00))

Ответы [ 4 ]

3 голосов
/ 23 января 2011

Я узнаю эту домашнюю работу:)

Похоже, что m - это Map, и вам не слишком важны ключи в выводе (возможно, вы уже использовали filterKeys к этому моменту), так что, вероятно, проще всего просто извлечь значения, а затем фильтровать избегайте всех этих утомительных кортежей и подчеркиваний ...

val values = m.values
val positives = values filter { _ >= 0 }
val negatives = values filter { _ < 0 }

Или, если хотите, это можно привести в порядок (и сделать более эффективным), используя метод partition:

val (positives,negatives) = m.values partition { _ >= 0 }

или даже использовать так называемый стиль «без точек», но это может слишком сильно его завести:

val (positives,negatives) = m.values partition { 0 < }

Теперь у вас не должно возникнуть проблем с выяснением, что делать с positives и negatives

1 голос
/ 23 января 2011

Вот решение:

val m = for ((k, v) <- d.groupBy(_._1.slice(0, 7))) yield k -> (for ((t, nums) <- (for ((s, l) <- (for ((date, num) <- v) yield (num, if (num > 0) 'positive else 'negative)).groupBy(_._2)) yield s -> (for ((num, _) <- l) yield num))) yield t -> nums.sum)

for ((month, nums) <- m; positive <- nums.get('positive) orElse Some(0D); negative <- nums.get('negative) orElse Some(0D)) {
  println("%7s %11.2f %11.2f %11.2f" format(month, positive, negative, positive + negative))
}

он дает тот же результат, что и ваше решение, и использует только slice, groupBy, sum, yield (кому нужно собирать :). Теперь еще одно испытание - вы должны попытаться понять это :) (и, возможно, оптимизировать)

1 голос
/ 23 января 2011

Я предполагаю, что вы используете карту карт, например Map [String, Map [String, Int]], в этом случае решение может выглядеть следующим образом:

val m = Map("hello" -> Map("a" -> 1, "b" -> -5, "c" -> 3, "d" -> -2))

val sums = m map {
  case (k, v) =>
    k -> (v.values partition (_ > 0) match {
      case (p, n) => (p.sum, n.sum)
    }).productIterator.toList
}

println(sums)

, и результат будет выглядеть следующим образом:

Map(hello -> List(4, -7))

, если вы все еще хотите использовать для понимания, это может выглядеть так:

for (w <- m) {
  val sums = (w._2.values.partition(_ > 0) match {
    case (p, n) => (p.sum, n.sum)
  }).productIterator.toList
}

(протестировано с Scala 2.8.1)

1 голос
/ 23 января 2011

Использовать рекурсию с внутренней функцией с использованием аккумулятора:

def sumIt(input:List[Tuple2[Int,Int]):Tuple2[Int,Int}={
    def sum_vals(entries:List[Tuple2[Int,Int]], acc:Tuple2[Int,Int]):Tuple2[Int,Int]={
        entries match{
            case x::xs => if(x._2 < 0){ 
                    sum_vals(xs, (acc._1, acc._2+x._2))
                } 
                else{ 
                    sum_vals(xs, (acc._1+x._2, acc._2))
                }
            case Nil => acc
        }
    }
    sum_vals(input, (0,0))
}

Где я предполагаю, что вы хотите, чтобы все отрицательные значения содержались в первом элементе возвращаемого кортежа, а отрицательные во втором.*

Редактировать:

FoldLeft, мне нужно думать о FoldLeft:

def sum_vals(left:Tuple2[Int,Int], right:Tuple2[Int,Int])={
    if(right._2 < 0){
        (left._1, left._2 + right._2)
    }
    else{
        (left._1+right._2, left._2)
    }
 }

myCollection.foldLeft((0,0))( x,y => sum_vals(x,y) )
...