복붙노트

[SCALA] 이 개지도를 병합과 같은 키의 값을 요약하는 가장 좋은 방법은?

SCALA

이 개지도를 병합과 같은 키의 값을 요약하는 가장 좋은 방법은?

val map1 = Map(1 -> 9 , 2 -> 20)
val map2 = Map(1 -> 100, 3 -> 300)

내가 그들을 병합하고, 같은 키의 값을 합계를. 그래서 결과는 다음과 같습니다

Map(2->20, 1->109, 3->300)

지금은이 개 솔루션을 가지고 :

val list = map1.toList ++ map2.toList
val merged = list.groupBy ( _._1) .map { case (k,v) => k -> v.map(_._2).sum }

val merged = (map1 /: map2) { case (map, (k,v)) =>
    map + ( k -> (v + map.getOrElse(k, 0)) )
}

그러나 나는 더 나은 솔루션이 있는지 알고 싶습니다.

해결법

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

    1.Scalaz은 여기에 수행 할 작업을 캡처하고 짧은 / 깨끗한 솔루션을 틀림없이에 이르게 이는 반군의 개념이 있습니다 :

    Scalaz은 여기에 수행 할 작업을 캡처하고 짧은 / 깨끗한 솔루션을 틀림없이에 이르게 이는 반군의 개념이 있습니다 :

    scala> import scalaz._
    import scalaz._
    
    scala> import Scalaz._
    import Scalaz._
    
    scala> val map1 = Map(1 -> 9 , 2 -> 20)
    map1: scala.collection.immutable.Map[Int,Int] = Map(1 -> 9, 2 -> 20)
    
    scala> val map2 = Map(1 -> 100, 3 -> 300)
    map2: scala.collection.immutable.Map[Int,Int] = Map(1 -> 100, 3 -> 300)
    
    scala> map1 |+| map2
    res2: scala.collection.immutable.Map[Int,Int] = Map(1 -> 109, 3 -> 300, 2 -> 20)
    

    특히,지도에 대한 이항 연산자 [K는 V] 중복 된 값을 통해 V의 반군 연산자를 접는,지도의 키를 결합합니다. 각 중복 키 값의 합계를 얻을 수 있도록 인터넷 용 표준 반군은 또한 연산자를 사용합니다.

    편집 : 조금 더 세부 사항, user482745의 요청에 따라.

    수학적 반군 함께 그 세트로부터 두 개의 값을 얻어 조작자와, 단지 값의 세트이며, 그 세트에서 다른 값을 생성한다. 또한 이하의 정수, 예를 들면 반군, 그래서 - + 연산자 다른 INT 있도록 두개의 int 결합.

    당신은 또한 당신이 어떻게 든 두 가지의 조합으로 새로운 하나를 생산하는 두 개의지도를 결합하여 몇 가지 동작을 가지고 올 수있는 너무 오래, "주어진 키 유형과 값 유형 모든지도"의 설정을 통해 반군을 정의 할 수 있습니다 입력.

    모두지도에 표시 키가없는 경우,이 간단하다. 같은 키를 두 맵에 존재하는 경우, 우리는 그 키 맵에 두 값을 결합해야합니다. 흠, 우리는 단지 동일한 유형의 두 가지 요소를 결합하는 연산자를 설명하지? 이 Scalaz에지도를위한 반군 [K는, V] 존재 이유가되는 것은, V의 반군이 존재하는 경우에만 - V의 반군이 같은 키에 할당 된 두 개의 맵에서 값을 결합하는 데 사용됩니다.

    지능 여기에 값 유형, 1 키의 "충돌"입니다 그래서 때문에 따라서, 값이 문자열 있었다면 100 + 9, A (즉 지능의 반군 운영자가하는 일의로) 두 매핑 된 값의 정수를 첨가하여 해결 (즉, 문자열에 대한 반군 운영자가하는 일이기 때문에, 다시) 충돌은 두 매핑 된 값의 문자열 연결 이어질 것입니다.

    !. 문자열 연결은 교환 법칙이 성립하지 않기 때문에 (그리고 흥미롭게도, - 즉, "A"+ "B"= "B"+ "는"- 결과 반군 작업 중 하나 그래서 MAP1 아니다 | + | MAP2는 MAP2 다르다 | + | 문자열의 경우 MAP1가 아니라 지능의 경우).

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

    2.나는이 알고있는 가장 짧은 대답은 표준 라이브러리가 사용

    나는이 알고있는 가장 짧은 대답은 표준 라이브러리가 사용

    map1 ++ map2.map{ case (k,v) => k -> (v + map1.getOrElse(k,0)) }
    
  3. ==============================

    3.빠른 솔루션 :

    빠른 솔루션 :

    (map1.keySet ++ map2.keySet).map {i=> (i,map1.getOrElse(i,0) + map2.getOrElse(i,0))}.toMap
    
  4. ==============================

    4.자, 이제 당신이 원하는 무언가가 스칼라 라이브러리 (최소 2.10에서)에서 - 기능을 통합. 하지만 그것은 단지의 HashMap에없는지도에 표시합니다. 그것은 다소 혼란입니다. 또한 서명은 복잡 - 내가 다른 키 쌍을 생성해야 할 것입니다 때 두 번 키를 필요로하고 줄 이유를 상상할 수 없다. 그러나 그럼에도 불구하고, 그것을 작동 이전의 "기본"솔루션보다 훨씬 청소기.

    자, 이제 당신이 원하는 무언가가 스칼라 라이브러리 (최소 2.10에서)에서 - 기능을 통합. 하지만 그것은 단지의 HashMap에없는지도에 표시합니다. 그것은 다소 혼란입니다. 또한 서명은 복잡 - 내가 다른 키 쌍을 생성해야 할 것입니다 때 두 번 키를 필요로하고 줄 이유를 상상할 수 없다. 그러나 그럼에도 불구하고, 그것을 작동 이전의 "기본"솔루션보다 훨씬 청소기.

    val map1 = collection.immutable.HashMap(1 -> 11 , 2 -> 12)
    val map2 = collection.immutable.HashMap(1 -> 11 , 2 -> 12)
    map1.merged(map2)({ case ((k,v1),(_,v2)) => (k,v1+v2) })
    

    또한 scaladoc에 언급

  5. ==============================

    5.이것은 그냥 일반 스칼라와 모노 이드로 구현 될 수있다. 다음은 샘플 구현입니다. 이 방법으로, 우리는 단지 2 만지도의 목록을 병합 할 수 있습니다.

    이것은 그냥 일반 스칼라와 모노 이드로 구현 될 수있다. 다음은 샘플 구현입니다. 이 방법으로, 우리는 단지 2 만지도의 목록을 병합 할 수 있습니다.

    // Monoid trait
    
    trait Monoid[M] {
      def zero: M
      def op(a: M, b: M): M
    }
    

    이 개지도를 병합 모노 이드의 특성의지도를 기반으로 구현.

    val mapMonoid = new Monoid[Map[Int, Int]] {
      override def zero: Map[Int, Int] = Map()
    
      override def op(a: Map[Int, Int], b: Map[Int, Int]): Map[Int, Int] =
        (a.keySet ++ b.keySet) map { k => 
          (k, a.getOrElse(k, 0) + b.getOrElse(k, 0))
        } toMap
    }
    

    당신이 통합 될 필요가 맵의 목록이있는 경우 지금 (이 경우, 단지 2)는 다음과 같이 수행 할 수 있습니다.

    val map1 = Map(1 -> 9 , 2 -> 20)
    val map2 = Map(1 -> 100, 3 -> 300)
    
    val maps = List(map1, map2) // The list can have more maps.
    
    val merged = maps.foldLeft(mapMonoid.zero)(mapMonoid.op)
    
  6. ==============================

    6.

    map1 ++ ( for ( (k,v) <- map2 ) yield ( k -> ( v + map1.getOrElse(k,0) ) ) )
    
  7. ==============================

    7.나는 이것에 대해 블로그 포스트를 작성, 그것을 체크 아웃 :

    나는 이것에 대해 블로그 포스트를 작성, 그것을 체크 아웃 :

    http://www.nimrodstech.com/scala-map-merge/

    기본적으로 scalaz 반 그룹을 사용하면 아주 쉽게이를 수 있습니다

    같이 보일 것입니다 :

      import scalaz.Scalaz._
      map1 |+| map2
    
  8. ==============================

    8.또한 고양이와 함께 그렇게 할 수 있습니다.

    또한 고양이와 함께 그렇게 할 수 있습니다.

    import cats.implicits._
    
    val map1 = Map(1 -> 9 , 2 -> 20)
    val map2 = Map(1 -> 100, 3 -> 300)
    
    map1 combine map2 // Map(2 -> 20, 1 -> 109, 3 -> 300)
    
  9. ==============================

    9.스칼라 2.13를 시작, 또 다른 솔루션 만 표준 라이브러리를 기반으로는 (그 이름에서 알 수 있듯이) mapValues ​​다음에 GROUPBY의 동등한와 감소 단계 groupMapReduce와 솔루션의 GROUPBY의 부품을 교체로 구성되어 있습니다 :

    스칼라 2.13를 시작, 또 다른 솔루션 만 표준 라이브러리를 기반으로는 (그 이름에서 알 수 있듯이) mapValues ​​다음에 GROUPBY의 동등한와 감소 단계 groupMapReduce와 솔루션의 GROUPBY의 부품을 교체로 구성되어 있습니다 :

    // val map1 = Map(1 -> 9, 2 -> 20)
    // val map2 = Map(1 -> 100, 3 -> 300)
    (map1.toSeq ++ map2).groupMapReduce(_._1)(_._2)(_+_)
    // Map[Int,Int] = Map(2 -> 20, 1 -> 109, 3 -> 300)
    

    이:

  10. ==============================

    10.여기에 내가 사용하는 결국 무엇을 :

    여기에 내가 사용하는 결국 무엇을 :

    (a.toSeq ++ b.toSeq).groupBy(_._1).mapValues(_.map(_._2).sum)
    
  11. ==============================

    11.의 Andrzej 도일의 대답은 당신이를 사용할 수 있습니다 반군의 좋은 설명을 포함 | + | 오퍼레이터는 두 맵 가입 키와 일치하는 값을 합산한다.

    의 Andrzej 도일의 대답은 당신이를 사용할 수 있습니다 반군의 좋은 설명을 포함 | + | 오퍼레이터는 두 맵 가입 키와 일치하는 값을 합산한다.

    뭔가가 typeclass의 인스턴스로 정의 할 수있는 많은 방법이 있고, 영업과는 달리 당신은 특별히 키를 합계를하지 않을 수 있습니다. 또는, 당신은 교차로가 아닌 노동 조합에서 작동 수행 할 수 있습니다. Scalaz는이 목적을 위해지도하는 추가 기능을 추가합니다 :

    https://oss.sonatype.org/service/local/repositories/snapshots/archive/org/scalaz/scalaz_2.11/7.3.0-SNAPSHOT/scalaz_2.11-7.3.0-SNAPSHOT-javadoc.jar/!/index.html#scalaz.std.MapFunctions

    넌 할 수있어

    import scalaz.Scalaz._
    
    map1 |+| map2 // As per other answers
    map1.intersectWith(map2)(_ + _) // Do things other than sum the values
    
  12. ==============================

    12.가장 빠르고 간단한 방법 :

    가장 빠르고 간단한 방법 :

    val m1 = Map(1 -> 1.0, 3 -> 3.0, 5 -> 5.2)
    val m2 = Map(0 -> 10.0, 3 -> 3.0)
    val merged = (m2 foldLeft m1) (
      (acc, v) => acc + (v._1 -> (v._2 + acc.getOrElse(v._1, 0.0)))
    )
    

    이 방법으로 요소의 각 즉시지도에 추가됩니다.

    두 번째 ++ 방법입니다 :

    map1 ++ map2.map { case (k,v) => k -> (v + map1.getOrElse(k,0)) }
    

    첫 번째 방법과는 달리, 두 번째지도의 각 요소에 대한 두 번째 방법으로 새로운 목록이 생성됩니다 이전지도에 연결된.

    CASE 표현식은 암시 적으로 적용 취소 방법을 사용하여 새 목록을 작성합니다.

  13. ==============================

    13.이것은 내가 생각 해낸 것입니다 ...

    이것은 내가 생각 해낸 것입니다 ...

    def mergeMap(m1: Map[Char, Int],  m2: Map[Char, Int]): Map[Char, Int] = {
       var map : Map[Char, Int] = Map[Char, Int]() ++ m1
       for(p <- m2) {
          map = map + (p._1 -> (p._2 + map.getOrElse(p._1,0)))
       }
       map
    }
    
  14. ==============================

    14.내가 일을 할 수있는 작은 기능을 가지고, 그것은 표준 lib 디렉토리에없는 자주 사용하는 기능을 내 작은 도서관에 있어요. 그것은 가변 및 불변의지도,뿐만 아니라 HashMaps을 모든 종류의 작업을해야

    내가 일을 할 수있는 작은 기능을 가지고, 그것은 표준 lib 디렉토리에없는 자주 사용하는 기능을 내 작은 도서관에 있어요. 그것은 가변 및 불변의지도,뿐만 아니라 HashMaps을 모든 종류의 작업을해야

    여기에 사용법은

    scala> import com.daodecode.scalax.collection.extensions._
    scala> val merged = Map("1" -> 1, "2" -> 2).mergedWith(Map("1" -> 1, "2" -> 2))(_ + _)
    merged: scala.collection.immutable.Map[String,Int] = Map(1 -> 2, 2 -> 4)
    

    https://github.com/jozic/scalax-collection/blob/master/README.md#mergedwith

    그리고 여기에 신체의

    def mergedWith(another: Map[K, V])(f: (V, V) => V): Repr =
      if (another.isEmpty) mapLike.asInstanceOf[Repr]
      else {
        val mapBuilder = new mutable.MapBuilder[K, V, Repr](mapLike.asInstanceOf[Repr])
        another.foreach { case (k, v) =>
          mapLike.get(k) match {
            case Some(ev) => mapBuilder += k -> f(ev, v)
            case _ => mapBuilder += k -> v
          }
        }
        mapBuilder.result()
      }
    

    https://github.com/jozic/scalax-collection/blob/master/src%2Fmain%2Fscala%2Fcom%2Fdaodecode%2Fscalax%2Fcollection%2Fextensions%2Fpackage.scala#L190

  15. ==============================

    15.typeclass 패턴을 사용하여, 우리는 모든 숫자 유형을 병합 할 수 있습니다 :

    typeclass 패턴을 사용하여, 우리는 모든 숫자 유형을 병합 할 수 있습니다 :

    object MapSyntax {
      implicit class MapOps[A, B](a: Map[A, B]) {
        def plus(b: Map[A, B])(implicit num: Numeric[B]): Map[A, B] = {
          b ++ a.map { case (key, value) => key -> num.plus(value, b.getOrElse(key, num.zero)) }
        }
      }
    }
    

    용법:

    import MapSyntax.MapOps
    
    map1 plus map2
    

    지도의 순서를 병합 :

    maps.reduce(_ plus _)
    
  16. from https://stackoverflow.com/questions/7076128/best-way-to-merge-two-maps-and-sum-the-values-of-same-key by cc-by-sa and MIT license