복붙노트

[SCALA] 스칼라에서 어떻게 SQL SUM 및 GROUP BY에 해당 할 수 있습니까?

SCALA

스칼라에서 어떻게 SQL SUM 및 GROUP BY에 해당 할 수 있습니까?

예를 들어, 내가 가진 가정

val list: List[(String, Double)]

"04-03-1985", 1.5
"05-03-1985", 2.4
"05-03-1985", 1.3

나는 새로운 목록을 생산할 수있는 방법

"04-03-1985", 1.5
"05-03-1985", 3.7

해결법

  1. ==============================

    1.여기에 한 줄입니다. 하나는 정말 이러한 고차 기능의 유형을 내면화하지 않는 한 그것은, 특히 읽을 수 없습니다.

    여기에 한 줄입니다. 하나는 정말 이러한 고차 기능의 유형을 내면화하지 않는 한 그것은, 특히 읽을 수 없습니다.

    val s = Seq(("04-03-1985" -> 1.5),
                ("05-03-1985" -> 2.4),
                ("05-03-1985" -> 1.3))
    
    s.groupBy(_._1).mapValues(_.map(_._2).sum)
    // returns: Map(04-03-1985 -> 1.5, 05-03-1985 -> 3.7)
    

    또 다른 방법은 하나씩는 배 사용하여 키 - 값 쌍을 추가하는 것입니다,

    s.foldLeft(Map[String, Double]()) { case (m, (k, v)) =>
      m + (k -> (v + m.getOrElse(k, 0d)))
    }
    

    이해에 대한 동등한 제 생각에 가장 접근

    var m = Map[String, Double]()
    for ((k, v) <- s) {
      m += k -> (v + m.getOrElse(k, 0d))
    }
    

    아마 뭔가 더 좋은이지도에 대한 Scalaz의 모노 이드 typeclass 수행 할 수 있습니다.

    당신이 toSeq 및 toMap 방법을 사용하여 맵 [K, V] 서열 [(K, V)] 사이의 변환을 할 수 있습니다.

    최신 정보. 좀 더 그것을 숙고 후에, 나는 자연의 추상화는 "multimap은"변환 될 것이라고 생각, 유형,

    def seqToMultimap[A, B](s: Seq[(A, B)]): Map[A, Seq[B]]
    

    하나의 개인 라이브러리에서 해당 암시 적 확장으로, 사람은 쓸 수 있습니다 :

    s.toMultimap.mapValues(_.sum)
    

    이것은 내 의견으로는, 모두의 깨끗한입니다!

  2. ==============================

    2.Scalaz를 사용하여 다른 가능성이있다.

    Scalaz를 사용하여 다른 가능성이있다.

    핵심은 M는 모노 이드 후 맵 [T, M]의 경우도 모노 이드이고,에 통지한다. 나는이 개지도, M1을 가지고 M2 있다면 각 비슷한 키, 그래서 그들을 추가 할 수있는이 수단은 요소 함께 추가됩니다.

    예를 들어, 맵 [문자열 목록 [문자열]]는 모노 이드 목록 [문자열] 때문에이 모노 이드입니다. 그래서 범위에서 적절한 모노 이드 인스턴스 주어, 나는 할 수 있어야한다 :

      val m1 = Map("a" -> List(1), "b" -> List(3))
      val m2 = Map("a" -> List(2))
    
      // |+| "adds" two elements of a Monoid together in Scalaz
      m1 |+| m2 === Map("a" -> List(1, 2), "b" -> List(3))
    

    워드 형의 모노 이드 인스턴스가 있기 때문에 귀하의 질문에 대해 우리는지도 [문자열, 지능]는 모노 이드 것을 볼 수 있습니다. 하자 그것을 가져옵니다

      implicit val mapMonoid = MapMonoid[String, Int]
    

    그럼,에 이동의와 모노 이드와의 요소 "추가"아무것도받는 함수의 reduceMonoid가 필요합니다. 난 그냥 전체 구현을 위해, 반복자 패턴의 본질에 내 게시물을 참조하시기 바랍니다, 여기에 reduceMonoid 정의를 쓰기 :

      // T is a "Traversable"
      def reduce[A, M : Monoid](reducer: A => M): T[A] => M
    

    사람들이 정의는 현재 Scalaz 라이브러리에 존재하지 않는 있지만 (기존의 모노 이드 및 트래버스 typeclasses 기준) 추가하기 어렵지 않다. 우리가 그들을 가지고 일단, 질문에 대한 해결책은 매우 간단합니다 :

      val s = Seq(("04-03-1985" -> 1.5),
                  ("05-03-1985" -> 2.4),
                  ("05-03-1985" -> 1.3))
    
       // we just put each pair in its own map and we let the Monoid instance
       // "add" the maps together
       s.reduceMonoid(Map(_)) === Map("04-03-1985" -> 1.5,
                                      "05-03-1985" -> 3.7)
    

    당신은 위의 코드하다고 생각하면 조금 모호하게 (그러나 정말 간결, 맞죠?), 나는 그것과 EIP 포스트 및 재생을위한 GitHub의 프로젝트를 확인하는 것이 좋습니다. 하나의 예를 보여줍니다 귀하의 질문에 대한 해결책 :

       "I can build a map String->Int" >> {
         val map1 = List("a" -> 1, "a" -> 2, "b" -> 3, "c" -> 4, "b" -> 5)
         implicit val mapMonoid = MapMonoid[String, Int]
    
         map1.reduceMonoid(Map(_)) must_== Map("a" -> 3, "b" -> 8, "c" -> 4)
       }
    
  3. ==============================

    3.그 패턴 s.groupBy (_._ 1) .mapValues ​​(_.지도 (_._ 2) .sum) Kipton의 대답에서 모든 시간을 사용했다. 그것은 꽤 직접 내 생각 프로세스를 변환하지만, 불행하게도 항상 읽기 쉬운 것이 아니다. 내가 찾은 그 때마다 가능하게 조금 더 나은 일 경우 클래스를 사용하여 :

    그 패턴 s.groupBy (_._ 1) .mapValues ​​(_.지도 (_._ 2) .sum) Kipton의 대답에서 모든 시간을 사용했다. 그것은 꽤 직접 내 생각 프로세스를 변환하지만, 불행하게도 항상 읽기 쉬운 것이 아니다. 내가 찾은 그 때마다 가능하게 조금 더 나은 일 경우 클래스를 사용하여 :

    case class Data(date: String, amount: Double)
    val t = s.map(t => (Data.apply _).tupled(t))
    // List(Data(04-03-1985,1.5), Data(05-03-1985,2.4), Data(05-03-1985,1.3))
    

    그 다음이된다 :

    t.groupBy(_.date).mapValues{ group => group.map(_.amount).sum }
    // Map(04-03-1985-> 1.5, 05-03-1985 -> 3.7)
    

    나는 다음 배 이상 또는 버전에 대한 더 읽을 생각합니다.

  4. ==============================

    4.

    val s = List ( "04-03-1985" -> 1.5, "05-03-1985" -> 2.4, "05-03-1985" -> 1.3)
    for { (key, xs) <- s.groupBy(_._1)
           x = xs.map(_._2).sum
        } yield (key, x)
    
  5. ==============================

    5.스칼라 2.13를 시작, (그 이름에서 알 수 있듯이) 당신은 mapValues ​​다음에 GROUPBY의 동등한입니다 groupMapReduce 방법을 사용할 수 있으며, 단계를 줄일 수 :

    스칼라 2.13를 시작, (그 이름에서 알 수 있듯이) 당신은 mapValues ​​다음에 GROUPBY의 동등한입니다 groupMapReduce 방법을 사용할 수 있으며, 단계를 줄일 수 :

    // val l = List(("04-03-1985", 1.5), ("05-03-1985", 2.4), ("05-03-1985", 1.3))
    l.groupMapReduce(_._1)(_._2)(_ + _).toList
    // List(("04-03-1985", 1.5), ("05-03-1985", 3.7))
    

    이:

    이 번역 할 수있는 일의 1 패스 버전입니다 :

    l.groupBy(_._1).mapValues(_.map(_._2).reduce(_ + _)).toList
    
  6. from https://stackoverflow.com/questions/7142514/in-scala-how-can-i-do-the-equivalent-of-an-sql-sum-and-group-by by cc-by-sa and MIT license