복붙노트

[SCALA] 스칼라 :지도의 컬렉션을 병합하는 방법

SCALA

스칼라 :지도의 컬렉션을 병합하는 방법

나는지도 [문자열, 더블]의 목록을 가지고 있고, 나는 하나의 맵 [문자열, 더블]에 그 내용을 병합하고 싶습니다. 어떻게 관용적 인 방법으로이 작업을 수행해야합니까? 나는이 배와 함께이 작업을 수행 할 수 있어야한다고 상상한다. 뭔가 같은 :

val newMap = Map[String, Double]() /: listOfMaps { (accumulator, m) => ... }

또한, 나는 일반적인 방법으로 키 충돌을 처리하고 싶습니다. 이미 존재한다는 것을, 나는 함수를 지정 할 수 있어야 내가지도에 키를 추가하는 경우 즉, 그 반환 (이 경우) 더블 및 해당 키에 대한 기존 값, 게다가 내가 추가 할 노력하고있어 값을 취 . 키가 아직지도에 존재하지 않는 경우, 그냥 그 값이 변경되지 않은 추가합니다.

내 특정 케이스에서 나는 하나의 맵 [문자열, 더블]지도 이미 키가 포함되어있는 경우, 다음 번 기존 맵 값에 추가됩니다하도록을 구축하고 싶습니다.

내 특정 코드에서 변경 가능한지도 함께 일하고 있어요,하지만 가능하면 내가 더 일반적인 솔루션에 관심이 있어요.

해결법

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

    1.이건 어때:

    이건 어때:

    def mergeMap[A, B](ms: List[Map[A, B]])(f: (B, B) => B): Map[A, B] =
      (Map[A, B]() /: (for (m <- ms; kv <- m) yield kv)) { (a, kv) =>
        a + (if (a.contains(kv._1)) kv._1 -> f(a(kv._1), kv._2) else kv)
      }
    
    val ms = List(Map("hello" -> 1.1, "world" -> 2.2), Map("goodbye" -> 3.3, "hello" -> 4.4))
    val mm = mergeMap(ms)((v1, v2) => v1 + v2)
    
    println(mm) // prints Map(hello -> 5.5, world -> 2.2, goodbye -> 3.3)
    

    그리고 그것은 2.7.5과 2.8.0에서 모두 작동합니다.

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

    2.글쎄, 당신은 할 수 있습니다 :

    글쎄, 당신은 할 수 있습니다 :

    mapList reduce (_ ++ _)
    

    충돌에 대한 특별한 요구 사항을 제외하고.

    당신은 특별한 요구 사항이 할 수 있기 때문에, 아마도 최고의는 다음과 같이 (2.8) 일 것이다 :

    def combine(m1: Map, m2: Map): Map = {
      val k1 = Set(m1.keysIterator.toList: _*)
      val k2 = Set(m2.keysIterator.toList: _*)
      val intersection = k1 & k2
    
      val r1 = for(key <- intersection) yield (key -> (m1(key) + m2(key)))
      val r2 = m1.filterKeys(!intersection.contains(_)) ++ m2.filterKeys(!intersection.contains(_)) 
      r2 ++ r1
    }
    

    그런 다음 포주 내 도서관 패턴을 통해지도 클래스에이 방법을 추가하고, 대신 "++"의 원래 예제에서 사용할 수 있습니다 :

    class CombiningMap(m1: Map[Symbol, Double]) {
      def combine(m2: Map[Symbol, Double]) = {
        val k1 = Set(m1.keysIterator.toList: _*)
        val k2 = Set(m2.keysIterator.toList: _*)
        val intersection = k1 & k2
        val r1 = for(key <- intersection) yield (key -> (m1(key) + m2(key)))
        val r2 = m1.filterKeys(!intersection.contains(_)) ++ m2.filterKeys(!intersection.contains(_))
        r2 ++ r1
      }
    }
    
    // Then use this:
    implicit def toCombining(m: Map[Symbol, Double]) = new CombiningMap(m)
    
    // And finish with:
    mapList reduce (_ combine _)
    

    keysIterator 2.7에 대한 키가되도록이가 2.8로 작성 동안 키, 필터는 필터와지도의 관점에서 작성해야, **되고, 등등, 너무 다른해서는 안됩니다 수 있습니다.

  3. ==============================

    3.나는 아무도 아직이 솔루션을 마련하지 놀라게하고 있습니다 :

    나는 아무도 아직이 솔루션을 마련하지 놀라게하고 있습니다 :

    myListOfMaps.flatten.toMap
    

    정확하게 당신이 필요합니까 :

    예:

    scala> List(Map('a -> 1), Map('b -> 2), Map('c -> 3), Map('a -> 4, 'b -> 5)).flatten.toMap
    res7: scala.collection.immutable.Map[Symbol,Int] = Map('a -> 4, 'b -> 5, 'c -> 3)
    

    회전을 튜플의 단순 목록으로 맵의 목록을 평평하게, toMap 모든 중복 키가 제거와 맵에 튜플의 목록을 회전

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

    4.(이 2.7.x에 대한 작업 또는 전혀 scalaz에있다처럼) 내가 뭔가를 누락하는 경우 그럴거야, 그래서 나는 빨리이 문제를 읽고 :

    (이 2.7.x에 대한 작업 또는 전혀 scalaz에있다처럼) 내가 뭔가를 누락하는 경우 그럴거야, 그래서 나는 빨리이 문제를 읽고 :

    import scalaz._
    import Scalaz._
    val ms = List(Map("hello" -> 1.1, "world" -> 2.2), Map("goodbye" -> 3.3, "hello" -> 4.4))
    ms.reduceLeft(_ |+| _)
    // returns Map(goodbye -> 3.3, hello -> 5.5, world -> 2.2)
    

    당신은 여기에 최대를 받고, 값을 축적하는 또 다른 방법을 두 번의 모노 이드의 정의를 변경하고 얻을 수 있습니다 :

    implicit val dbsg: Semigroup[Double] = semigroup((a,b) => math.max(a,b))
    ms.reduceLeft(_ |+| _)
    // returns Map(goodbye -> 3.3, hello -> 4.4, world -> 2.2)
    
  5. ==============================

    5.재미있는,이 비트와 함께 주변에 noodling, 내가있어 (2.7.5에서) 다음 :

    재미있는,이 비트와 함께 주변에 noodling, 내가있어 (2.7.5에서) 다음 :

    일반지도 :

       def mergeMaps[A,B](collisionFunc: (B,B) => B)(listOfMaps: Seq[scala.collection.Map[A,B]]): Map[A, B] = {
        listOfMaps.foldLeft(Map[A, B]()) { (m, s) =>
          Map(
            s.projection.map { pair =>
            if (m contains pair._1)
              (pair._1, collisionFunc(m(pair._1), pair._2))
            else
              pair
          }.force.toList:_*)
        }
      }
    

    그러나 프로젝션과 강제력과 toList와 이것 저것와 끔찍한이다 남자. 별도의 질문 : 배 내에서 그 처리하는 더 좋은 방법은 무엇입니까?

    내 코드에서 처리하고, 덜 일반적인 솔루션으로 된 것입니다 변경할지도, 위해, 나는이있어 :

    def mergeMaps[A,B](collisionFunc: (B,B) => B)(listOfMaps: List[mutable.Map[A,B]]): mutable.Map[A, B] = {
        listOfMaps.foldLeft(mutable.Map[A,B]()) {
          (m, s) =>
          for (k <- s.keys) {
            if (m contains k)
              m(k) = collisionFunc(m(k), s(k))
            else
              m(k) = s(k)
          }
          m
        }
      }
    

    즉 조금 청소기를 보인다 있지만 변경할지도 만 작업 기록의 뜻으로. 대신 foldLeft의,하지만 난 종류의 오류를 얻고 있었다 : 흥미롭게도, / 사용 (필자는 질문을하기 전에) 내가 먼저 위의 시도. 나는 / 생각 : 및 foldLeft는 기본적으로 동등했지만, 컴파일러는 내가 명시 적 유형 (M, S)을 필요로 불평을 유지했다. 그 무엇이야?

  6. ==============================

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

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

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

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

    같이 보일 것입니다 :

      import scalaz.Scalaz._
      listOfMaps reduce(_ |+| _)
    
  7. ==============================

    7.스칼라 2.13부터 중복 키를 처리만을 표준 라이브러리에 기초하여 또 다른 용액 (이름 그대로) GROUPBY는 다음에 등가 인 새로운 groupMapReduce 연산자를 적용하기 전에 시퀀스 (편평한)로 맵을 병합하는 것으로 이루어진다 매핑 및 그룹화 값의 감소 단계 :

    스칼라 2.13부터 중복 키를 처리만을 표준 라이브러리에 기초하여 또 다른 용액 (이름 그대로) GROUPBY는 다음에 등가 인 새로운 groupMapReduce 연산자를 적용하기 전에 시퀀스 (편평한)로 맵을 병합하는 것으로 이루어진다 매핑 및 그룹화 값의 감소 단계 :

    List(Map("hello" -> 1.1, "world" -> 2.2), Map("goodbye" -> 3.3, "hello" -> 4.4))
      .flatten
      .groupMapReduce(_._1)(_._2)(_ + _)
    // Map("world" -> 2.2, "goodbye" -> 3.3, "hello" -> 5.5)
    

    이:

    groupMapReduce 단계의 원 - 패스 버전 동등한 것으로 볼 수있다 :

    list.groupBy(_._1).mapValues(_.map(_._2).reduce(_ + _))
    
  8. ==============================

    8.그 사용 scalaz를 사용하는 것과 거의 같은 깨끗한 읽는 oneliner 도우미-FUNC :

    그 사용 scalaz를 사용하는 것과 거의 같은 깨끗한 읽는 oneliner 도우미-FUNC :

    def mergeMaps[K,V](m1: Map[K,V], m2: Map[K,V])(f: (V,V) => V): Map[K,V] =
        (m1 -- m2.keySet) ++ (m2 -- m1.keySet) ++ (for (k <- m1.keySet & m2.keySet) yield { k -> f(m1(k), m2(k)) })
    
    val ms = List(Map("hello" -> 1.1, "world" -> 2.2), Map("goodbye" -> 3.3, "hello" -> 4.4))
    ms.reduceLeft(mergeMaps(_,_)(_ + _))
    // returns Map(goodbye -> 3.3, hello -> 5.5, world -> 2.2)
    

    궁극의 가독성에 대한 암시 적 정의 유형에 포장 :

    class MyMap[K,V](m1: Map[K,V]) {
        def merge(m2: Map[K,V])(f: (V,V) => V) =
        (m1 -- m2.keySet) ++ (m2 -- m1.keySet) ++ (for (k <- m1.keySet & m2.keySet) yield { k -> f(m1(k), m2(k)) })
    }
    implicit def toMyMap[K,V](m: Map[K,V]) = new MyMap(m)
    
    val ms = List(Map("hello" -> 1.1, "world" -> 2.2), Map("goodbye" -> 3.3, "hello" -> 4.4))
    ms reduceLeft { _.merge(_)(_ + _) } 
    
  9. from https://stackoverflow.com/questions/1262741/scala-how-to-merge-a-collection-of-maps by cc-by-sa and MIT license