복붙노트

[SCALA] 규모 :지도 병합

SCALA

규모 :지도 병합

어떻게하면 아래와 같은지도를 병합 할 수 있습니다 :

Map1 = Map(1 -> Class1(1), 2 -> Class1(2))
Map2 = Map(2 -> Class2(1), 3 -> Class2(2))

후 합병했다.

Merged = Map( 1 -> List(Class1(1)), 2 -> List(Class1(2), Class2(1)), 3 -> Class2(2))

목록, 설정 또는 크기 속성이 다른 수집 할 수 있습니다.

해결법

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

    1.다음과 같이 표준 라이브러리를 사용하여, 당신은 그것을 할 수 있습니다 :

    다음과 같이 표준 라이브러리를 사용하여, 당신은 그것을 할 수 있습니다 :

    // convert maps to seq, to keep duplicate keys and concat
    val merged = Map(1 -> 2).toSeq ++ Map(1 -> 4).toSeq
    // merged: Seq[(Int, Int)] = ArrayBuffer((1,2), (1,4))
    
    // group by key
    val grouped = merged.groupBy(_._1)
    // grouped: scala.collection.immutable.Map[Int,Seq[(Int, Int)]] = Map(1 -> ArrayBuffer((1,2), (1,4)))
    
    
    // remove key from value set and convert to list
    val cleaned = grouped.mapValues(_.map(_._2).toList)
    // cleaned: scala.collection.immutable.Map[Int,List[Int]] = Map(1 -> List(2, 4))
    
  2. ==============================

    2.이것은 내가 가지고 올 수있는 간단한 구현

    이것은 내가 가지고 올 수있는 간단한 구현

    val m1 = Map(1 -> "1", 2 -> "2")
    val m2 = Map(2 -> "21", 3 -> "3")
    
    def merge[K, V](m1:Map[K, V], m2:Map[K, V]):Map[K, List[V]] = 
      (m1.keySet ++ m2.keySet) map { i => i -> (m1.get(i).toList ::: m2.get(i).toList) } toMap
    
    merge(m1, m2) // Map(1 -> List(1), 2 -> List(2, 21), 3 -> List(3))
    
  3. ==============================

    3.당신은 scalaz를 사용할 수 있습니다 :

    당신은 scalaz를 사용할 수 있습니다 :

    import scalaz._, Scalaz._
    
    val m1 = Map('a -> 1, 'b -> 2)
    val m2 = Map('b -> 3, 'c -> 4)
    
    m1.mapValues{List(_)} |+| m2.mapValues{List(_)}
    // Map('b -> List(2, 3), 'c -> List(4), 'a -> List(1))
    

    당신은지도에있는 값으로 설정을 얻기 위해 설정 (_) 대신 목록 (_)을 사용할 수 있습니다.

    scalaz의 컨닝 페이퍼에 반군을 참조하십시오 (또는 scalaz을 학습)에 대한 자세한 내용은 | + | 운영자.

    인터넷 용 | + | + | | - 목록 +로 작동 ++로지도를 위해 적용 동일한 키 값.

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

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

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

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

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

    같이 보일 것입니다 :

      import scalaz.Scalaz._
      Map1 |+| Map2
    
  5. ==============================

    5.한 깨끗한 방법은 고양이와 함께, 그것을 할 수 있습니다 :

    한 깨끗한 방법은 고양이와 함께, 그것을 할 수 있습니다 :

    import cats.implicits._
    
    Map(1 -> "Hello").combine(Map(2 -> "Goodbye"))
    //Map(2 -> Goodbye, 1 -> Hello)
    

    이 두지도는 동일한 유형 (이 경우, 맵 [INT, 문자열])이 될 필요가 있음을주의하는 것이 중요합니다.

    긴 설명 :

    결합 정말지도의 구성원이 아닙니다. cats.implicits를 가져 오면 당신은 간결한 구문을 수 있도록 몇 가지 암시 클래스와 함께, 내장 된 모노 이드 인스턴스 범위 고양이의지도로 데려 와야합니다.

    상기이 동등하다 :

    Monoid[Map[Int, String]].combine(Map(1 -> "Hello"), Map(2 -> "Goodbye"))
    

    우리가 범위의 모노 이드 [맵 [INT, 문자열]] 인스턴스를 얻기 위해 모노 이드 "소환"기능을 사용하여 사용하는 경우 그 기능을 결합합니다.

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

    6.동일한 유형의 두지도를 병합 foldLeft을 사용할 수 있습니다

    동일한 유형의 두지도를 병합 foldLeft을 사용할 수 있습니다

    def merge[A, B](a: Map[A, B], b: Map[A, B])(mergef: (B, Option[B]) => B): Map[A, B] = {
      val (big, small) = if (a.size > b.size) (a, b) else (b, a)
      small.foldLeft(big) { case (z, (k, v)) => z + (k -> mergef(v, z.get(k))) }
    }
    
    def mergeIntSum[A](a: Map[A, Int], b: Map[A, Int]): Map[A, Int] =
      merge(a, b)((v1, v2) => v2.map(_ + v1).getOrElse(v1))
    

    예:

    val a = Map("a" -> 1, "b" -> 5, "c" -> 6)
    val b = Map("a" -> 4, "z" -> 8)
    mergeIntSum(a, b)
    res0: Map[String,Int] = Map(a -> 5, b -> 5, c -> 6, z -> 8)
    
  7. ==============================

    7.스칼라 2.13부터 만 표준 라이브러리에 기초하여 또 다른 해결책은 (그 이름에서 알 수 있듯이) mapValues ​​뒤에 GROUPBY의 상당에서는 groupMap를 사용하여 구성되어

    스칼라 2.13부터 만 표준 라이브러리에 기초하여 또 다른 해결책은 (그 이름에서 알 수 있듯이) mapValues ​​뒤에 GROUPBY의 상당에서는 groupMap를 사용하여 구성되어

    // val m1 = Map(1 -> "a", 2 -> "b")
    // val m2 = Map(2 -> "c", 3 -> "d")
    (m1.toSeq ++ m2).groupMap(_._1)(_._2)
    // Map[Int,Seq[String]] = Map(2 -> List("b", "c"), 1 -> List("a"), 3 -> List("d"))
    

    이:

  8. ==============================

    8.당신이 원래의지도를 허비하지 않으려면 다음과 같은 일을 할 수있는

    당신이 원래의지도를 허비하지 않으려면 다음과 같은 일을 할 수있는

    val target = map1.clone()
    val source = map2.clone()
    source.foreach(e => target += e._1 -> e._2)
    
  9. ==============================

    9.

    left.keys map { k => k -> List(left(k),right(k)) } toMap
    

    간결하고 두 개의지도가 좌우되는 가정 작동합니다. 효율이 확실하지 않음.

    그러나 귀하의 질문은 두 가지 이유로, 조금 모호합니다. 당신은 지정하지 않는

    첫 번째 경우를 들어, 다음 예제를 고려하십시오

    val left = Map("foo" ->1, "bar" ->2)
    val right = Map("bar" -> 'a', "foo" -> 'b')
    

    어떤 결과

    res0: Map[String,List[Int]] = Map(foo -> List(1, 98), bar -> List(2, 97))
    

    숯을 때문에 스칼라 유형 계층 구조의,의 int로 변환 된 방법을 알 수 있습니다. 귀하의 예를 들어 클래스 1과 Class2의에 관련이없는 경우보다 일반적으로, 당신은 목록 [모든]을 다시 얻을 것; 이것은 아마 당신이 원하지 없습니다.

    당신은 내 대답에서 목록 생성자를 놓는 방법으로이 문제를 해결할 수있다; 이 유형을 유지하는 튜플을 반환합니다 :

    res0: Map[String,(Int, Char)] = Map(foo -> (1,b), bar -> (2,a))
    

    두 번째 문제는 같은 키가없는지도가있을 때 발생하는 것입니다. 이는 키가 아닌 발견 예외가 발생합니다. 또 다른 방법으로 넣어, 당신은 오른쪽 왼쪽을하고, 또는 내부는 두지도의 조인입니까? 당신은 권리를 위해 right.keys 또는 right.keySet ++ left.keySet로 전환하여 조인의 종류를 명확하게 할 수 / 내부는 각각 합류했다. 후자는 누락 된 핵심 문제를 해결하지만, 어쩌면 당신이 왼쪽을 원하거나를 대신 가입 즉 아마 원하는 게 아니에요. 이 경우 당신은, 예를 들어, 값을 모든 키 수익률을 보장하기 위해지도의 withDefault 방법을 고려할 수 있습니다 없음, 그러나 이것은 조금 더 많은 작업을 필요로하지 않는다.

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

    10.

    m2.foldLeft(m1.mapValues{List[CommonType](_)}) { case (acc, (k, v)) =>
      acc.updated(k, acc.getOrElse(k, List.empty) :+ v)
    }
    

    jwvh에서 언급 한 바와 같이, 목록 유형은 클래스 1은 Class2의 행 위 형식이 아닌 경우 명시 적으로 지정해야합니다. CommonType는 클래스 1과 Class2의 모두 상한 인 유형입니다.

  11. ==============================

    11.솔루션이 개지도를 결합하기 : 맵 [A, B], 결과 유형 :지도 [A, 목록 [B] (@ 데이비드 카 스틸로가 제공하는 약간 개선 된 버전) 스칼라 고양이를 통해

    솔루션이 개지도를 결합하기 : 맵 [A, B], 결과 유형 :지도 [A, 목록 [B] (@ 데이비드 카 스틸로가 제공하는 약간 개선 된 버전) 스칼라 고양이를 통해

    // 각 원래지도 [A, 목록 [B]]지도로 변환합니다. // 목록을 결합하는 범위에 모노 이드 [목록]의 인스턴스를 추가 :

    import cats.instances.map._ // for Monoid
    import cats.syntax.semigroup._ // for |+|
    import cats.instances.list._
    
    val map1 = Map("a" -> 1, "b" -> 2)
      .mapValues(List(_))
    val map2 = Map("b" -> 3, "d" -> 4)
      .mapValues(List(_))
    map1 |+| map2
    
  12. ==============================

    12.mergeByKey 같은 매우 유용한 방법을 제공 스칼라 수집-있는 contrib라는 스칼라 모듈은있다.

    mergeByKey 같은 매우 유용한 방법을 제공 스칼라 수집-있는 contrib라는 스칼라 모듈은있다.

    첫째, 우리는 build.sbt에 추가 종속성을 추가해야합니다

    libraryDependencies += "org.scala-lang.modules" %% "scala-collection-contrib" % "0.1.0"
    

    후는 다음과 같이 병합 할 수있다 :

    import scala.collection.decorators._
    
    val map1 = Map(1 -> Class1(1), 2 -> Class1(2))
    val map2 = Map(2 -> Class2(1), 3 -> Class2(2))
    
    map1.mergeByKeyWith(map2){
      case (a,b) => a.toList ++ b.toList
    }
    
  13. from https://stackoverflow.com/questions/20047080/scala-merge-map by cc-by-sa and MIT license