복붙노트

[SCALA] 스칼라의지도를 반전하는 우아한 방법

SCALA

스칼라의지도를 반전하는 우아한 방법

학습 스칼라는 현재 일부 역 부가가치> 키 조회를 할 수있는지도를 반전 할 필요가 있었다. 나는이 작업을 수행 할 수있는 간단한 방법을 찾고 있지만 내놓았다했다 :

(Map() ++ origMap.map(kvp=>(kvp._2->kvp._1)))

누구는 더 우아한 방법이 있나요?

해결법

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

    1.가정 값은,이 작품 고유 :

    가정 값은,이 작품 고유 :

    (Map() ++ origMap.map(_.swap))
    

    스칼라 2.8에, 그러나, 그것은 쉽게 :

    origMap.map(_.swap)
    

    그렇게 할 수있는 것은 스칼라 2.8은 새 컬렉션 라이브러리를 가지고 이유의 일부입니다.

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

    2.수학적으로, 매핑은 예를 들어, 맵 [A, B]에서, 당신은지도 [B, A]를 얻을 수 없다, 가역 (단사)하지 않을 수 있습니다, 그러나 오히려 당신은지도 얻을 [B, 세트 [A], 때문에이 같은 값과 관련된 다른 키 수 있습니다. 당신이 모든 열쇠를 알고에 관심이 있다면 그래서, 여기에 코드입니다 :

    수학적으로, 매핑은 예를 들어, 맵 [A, B]에서, 당신은지도 [B, A]를 얻을 수 없다, 가역 (단사)하지 않을 수 있습니다, 그러나 오히려 당신은지도 얻을 [B, 세트 [A], 때문에이 같은 값과 관련된 다른 키 수 있습니다. 당신이 모든 열쇠를 알고에 관심이 있다면 그래서, 여기에 코드입니다 :

    scala> val m = Map(1 -> "a", 2 -> "b", 4 -> "b")
    scala> m.groupBy(_._2).mapValues(_.keys)
    res0: Map[String,Iterable[Int]] = Map(b -> Set(2, 4), a -> Set(1))
    
  3. ==============================

    3.몇 가지 방법으로 반복하는 동안 당신은 ._1 물건을 피할 수 있습니다.

    몇 가지 방법으로 반복하는 동안 당신은 ._1 물건을 피할 수 있습니다.

    여기 하나의 방법입니다. 이 부분 기능을 사용하는 커버 유일 사건을 그지도에 대한 문제 :

    Map() ++ (origMap map {case (k,v) => (v,k)})
    

    여기에 또 다른 방법이있다 :

    import Function.tupled        
    Map() ++ (origMap map tupled {(k,v) => (v,k)})
    

    지도의 반복은 2 개 요소 튜플을 가진 함수를 호출하고, 익명 함수는 두 개의 매개 변수를 원한다. Function.tupled는 번역을합니다.

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

    4.난의지도를 반전 할 수있는 방법을 찾고 여기 온 유형의지도 [A, 서열 [B]] 새로운 맵에서 각 B가의 옛지도에있는 모든와 관련된지도 [A] B, 서열 []에 이는 B가 A의 관련 시퀀스에 포함시켰다.

    난의지도를 반전 할 수있는 방법을 찾고 여기 온 유형의지도 [A, 서열 [B]] 새로운 맵에서 각 B가의 옛지도에있는 모든와 관련된지도 [A] B, 서열 []에 이는 B가 A의 관련 시퀀스에 포함시켰다.

    예를 들면, 지도 (1 -> 서열 ( "A", "B"), 2-> 서열 ( "B", "C")) 에 반전 것 지도 ( "A"-> 서열 1, "B"-> 서열 (1, 2), "C"-> 서열 2)

    여기 내 솔루션입니다 :

    val newMap = oldMap.foldLeft(Map[B, Seq[A]]().withDefaultValue(Seq())) {
      case (m, (a, bs)) => bs.foldLeft(m)((map, b) => map.updated(b, m(b) :+ a))
    }
    

    oldMap는 유형이다지도 [A 서열 [B] 및 newMap 형 맵 [B 서열 [A]이며

    중첩 된 foldLefts 나를 조금 싫증이 나다하게, 그러나 이것은 내가 반전의이 유형을 달성하기 위해 찾을 수있는 가장 간단한 방법입니다. 사람은 청소기 솔루션을?

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

    5.좋아, 그럼이 많은 좋은 답변 아주 오래된 질문이다,하지만 궁극적 될-모든 및 엔드 - 모든, 스위스 군용 칼,지도 인버터를 내장 한이 그것을 게시 할 수있는 곳입니다.

    좋아, 그럼이 많은 좋은 답변 아주 오래된 질문이다,하지만 궁극적 될-모든 및 엔드 - 모든, 스위스 군용 칼,지도 인버터를 내장 한이 그것을 게시 할 수있는 곳입니다.

    실제로 2 개의 인버터입니다. 개별 값 요소에 대한 하나의 ...

    //from Map[K,V] to Map[V,Set[K]], traverse the input only once
    implicit class MapInverterA[K,V](m :Map[K,V]) {
      def invert :Map[V,Set[K]] =
        m.foldLeft(Map.empty[V, Set[K]]) {
          case (acc,(k, v)) => acc + (v -> (acc.getOrElse(v,Set()) + k))
        }
    }
    

    ... 그리고 또 다른, 매우 유사한 값 모음.

    import scala.collection.generic.CanBuildFrom
    import scala.collection.mutable.Builder
    import scala.language.higherKinds
    
    //from Map[K,C[V]] to Map[V,C[K]], traverse the input only once
    implicit class MapInverterB[K,V,C[_]](m :Map[K,C[V]]
                                         )(implicit ev :C[V] => TraversableOnce[V]) {
      def invert(implicit bf :CanBuildFrom[Nothing,K,C[K]]) :Map[V,C[K]] =
        m.foldLeft(Map.empty[V, Builder[K,C[K]]]) {
          case (acc, (k, vs)) =>
            vs.foldLeft(acc) {
              case (a, v) => a + (v -> (a.getOrElse(v,bf()) += k))
            }
        }.mapValues(_.result())
    }
    

    용법:

    Map(2 -> Array('g','h'), 5 -> Array('g','y')).invert
    //res0: Map(g -> Array(2, 5), h -> Array(2), y -> Array(5))
    
    Map('q' -> 1.1F, 'b' -> 2.1F, 'c' -> 1.1F, 'g' -> 3F).invert
    //res1: Map(1.1 -> Set(q, c), 2.1 -> Set(b), 3.0 -> Set(g))
    
    Map(9 -> "this", 8 -> "that", 3 -> "thus", 2 -> "thus").invert
    //res2: Map(this -> Set(9), that -> Set(8), thus -> Set(3, 2))
    
    Map(1L -> Iterator(3,2), 5L -> Iterator(7,8,3)).invert
    //res3: Map(3 -> Iterator(1, 5), 2 -> Iterator(1), 7 -> Iterator(5), 8 -> Iterator(5))
    
    Map.empty[Unit,Boolean].invert
    //res4: Map[Boolean,Set[Unit]] = Map()
    

    저도 같은 암시 클래스의 두 가지 방법을 가지고하는 것을 선호하지만 난 소요되는 시간은 등장 더 문제가 그것으로 찾고.

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

    6.당신은 사용하여지도를 반전 할 수 :

    당신은 사용하여지도를 반전 할 수 :

    val i = origMap.map({case(k, v) => v -> k})
    

    이 방법의 문제는 이제 맵의 해시 키가되었습니다 당신의 가치는, 고유하지 않은 경우 중복 값을 드롭하는 것입니다. 설명하기 :

    scala> val m = Map("a" -> 1, "b" -> 2, "c" -> 3, "d" -> 1)
    m: scala.collection.immutable.Map[String,Int] = Map(a -> 1, b -> 2, c -> 3, d -> 1)
    
    // Notice that 1 -> a is not in our inverted map
    scala> val i = m.map({ case(k , v) => v -> k})
    i: scala.collection.immutable.Map[Int,String] = Map(1 -> d, 2 -> b, 3 -> c)
    

    이를 방지하기 위해 당신은 당신이 중복 값을 떨어 뜨리지 않도록 다음, 반전, 첫번째 튜플의 목록에지도를 변환 할 수 있습니다 :

    scala> val i = m.toList.map({ case(k , v) => v -> k})
    i: List[(Int, String)] = List((1,a), (2,b), (3,c), (1,d))
    
  7. ==============================

    7.스칼라 REPL에서 :

    스칼라 REPL에서 :

    scala> val m = Map(1 -> "one", 2 -> "two")
    m: scala.collection.immutable.Map[Int,java.lang.String] = Map(1 -> one, 2 -> two)
    
    scala> val reversedM = m map { case (k, v) => (v, k) }
    reversedM: scala.collection.immutable.Map[java.lang.String,Int] = Map(one -> 1, two -> 2)
    

    중복 값이 ​​맵에 마지막으로 첨가하여 덮어 될 것 참고 :

    scala> val m = Map(1 -> "one", 2 -> "two", 3 -> "one")
    m: scala.collection.immutable.Map[Int,java.lang.String] = Map(1 -> one, 2 -> two, 3 -> one)
    
    scala> val reversedM = m map { case (k, v) => (v, k) }
    reversedM: scala.collection.immutable.Map[java.lang.String,Int] = Map(one -> 3, two -> 2)
    
  8. ==============================

    8.스칼라 2.13 시작, 스왑 키 위해 / 같은 값에 관련된 키를 잃어버린없이 값, 우리는지도를 (그 이름에서 알 수 있듯이)는 GROUPBY의 동등한 및 그룹화 항목에 걸쳐 매핑 새로운에서는 groupMap 방법을 사용할 수 있습니다.

    스칼라 2.13 시작, 스왑 키 위해 / 같은 값에 관련된 키를 잃어버린없이 값, 우리는지도를 (그 이름에서 알 수 있듯이)는 GROUPBY의 동등한 및 그룹화 항목에 걸쳐 매핑 새로운에서는 groupMap 방법을 사용할 수 있습니다.

    Map(1 -> "a", 2 -> "b", 4 -> "b").groupMap(_._2)(_._1)
    // Map("b" -> List(2, 4), "a" -> List(1))
    

    이:

    이것은 map.groupBy (_._ 2) .mapValues의 원 - 패스 버전으로 볼 수있다 (_., MAP (_._ 1)).

  9. ==============================

    9.이 일대일지도가 있다면, 당신은 하찮게지도 [B, A]가 아니라 맵 [B, 목록 [A]에 테스트 변환 할 수 단일 목록으로 끝낼.

    이 일대일지도가 있다면, 당신은 하찮게지도 [B, A]가 아니라 맵 [B, 목록 [A]에 테스트 변환 할 수 단일 목록으로 끝낼.

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

    10.우리는 충돌을 돌봐 단일 주사로지도를 반전 할이 foldLeft 기능을 사용하여 시도 할 수 있습니다.

    우리는 충돌을 돌봐 단일 주사로지도를 반전 할이 foldLeft 기능을 사용하여 시도 할 수 있습니다.

    scala> def invertMap[A, B](inputMap: Map[A, B]): Map[B, List[A]] = {
         |     inputMap.foldLeft(Map[B, List[A]]()) {
         |       case (mapAccumulator, (value, key)) =>
         |         if (mapAccumulator.contains(key)) {
         |           mapAccumulator.updated(key, mapAccumulator(key) :+ value)
         |         } else {
         |           mapAccumulator.updated(key, List(value))
         |         }
         |     }
         |   }
    invertMap: [A, B](inputMap: Map[A,B])Map[B,List[A]]
    
    scala> val map = Map(1 -> 2, 2 -> 2, 3 -> 3, 4 -> 3, 5 -> 5)
    map: scala.collection.immutable.Map[Int,Int] = Map(5 -> 5, 1 -> 2, 2 -> 2, 3 -> 3, 4 -> 3)
    
    scala> invertMap(map)
    res0: Map[Int,List[Int]] = Map(5 -> List(5), 2 -> List(1, 2), 3 -> List(3, 4))
    
    scala> val map = Map("A" -> "A", "B" -> "A", "C" -> "C", "D" -> "C", "E" -> "E")
    map: scala.collection.immutable.Map[String,String] = Map(E -> E, A -> A, B -> A, C -> C, D -> C)
    
    scala> invertMap(map)
    res1: Map[String,List[String]] = Map(E -> List(E), A -> List(A, B), C -> List(C, D))
    
  11. from https://stackoverflow.com/questions/2338282/elegant-way-to-invert-a-map-in-scala by cc-by-sa and MIT license