2017-01-05 1 views
2

지도가 Map[A, Map[B, C]]입니다.스칼라에서 중첩 된지도를 역으로

지도를 역으로 변환하여 Map[B, Map[A, C]] 유형의지도를 만들려면 어떻게해야합니까?

+9

당신이지도'으로 어떻게 할 것인지 (1 ->지도 (2 -> 3), (10) ->지도 (2 -> 4))', 중복되는'B'가 있는가? –

+0

@MichaelZajac 어쩌면 나는 의도를 오해하고있다.하지만'Map (2 -> Map (1 -> 3, 10 -> 4)) '의 무엇이 잘못 되었습니까? –

+1

@TravisBrown 전혀 없습니다. OP가지도를 결합하고 싶다면 나는 몰랐다. –

답변

6

이 작업을 정의하는 데는 여러 가지 방법이 있습니다. 나는 내가 가장 명확한 것을 발견 한 몇 가지를 걷게 될 것이다. 첫 번째 구현을 위해 내가 도우미 메서드로 시작합니다 :

def flattenNestedMap[A, B, C](nested: Map[A, Map[B, C]]): Map[(A, B), C] = 
    for { 
    (a, innerMap) <- nested 
    (b, c)  <- innerMap 
    } yield (a, b) -> c 

이 값 쌍에서지도에 중첩 된지도를 평평하게. 다음으로 우리는 우리에게 필요한 것을 거의 얻을 수있는 또 다른 도우미 연산을 정의 할 수 있습니다.

def invert[A, B, C](nested: Map[A, Map[B, C]]): Map[B, Map[A, C]] = 
    groupByBs(flattenNestedMap(nested)).mapValues(
    _.map { 
     case ((a, _), c) => a -> c 
    } 
) 

(mapValues이 결과는 당신이 사용할 때마다 다시 계산된다는 것을 의미하는 게으른 것을 참고 :

def groupByBs[A, B, C](flattened: Map[(A, B), C]): Map[B, Map[(A, B), C]] = 
    flattened.groupBy(_._1._2) 

지금 우리는 단지 내부 맵의 키에서 중복 B를 제거해야 . 그것은 일반적으로이 문제가되지 않습니다, 쉬운 해결 방법이 있습니다,하지만 그들은 질문에 정말 관련이없는 것)

그리고 우리는 완료 :.

scala> invert(Map(1 -> Map(2 -> 3), 10 -> Map(2 -> 4))) 
res0: Map[Int,Map[Int,Int]] = Map(2 -> Map(1 -> 3, 10 -> 4)) 

도우미 메서드를 건너 뛰고 연산을 invert에 연결할 수 있습니다. 나는 그것들을 조금 더 명확하게 부 풀리는 것을 발견했다. 그러나 그것은 스타일의 문제 다.

scala> invert(Map(1 -> Map(2 -> 3), 10 -> Map(2 -> 4))) 
res1: Map[Int,Map[Int,Int]] = Map(2 -> Map(1 -> 3, 10 -> 4)) 

foldLeft 버전은 간단 필수적 버전 로지텍은의 모양을 더 가지고 같은 일을

def invert[A, B, C](nested: Map[A, Map[B, C]]): Map[B, Map[A, C]] = 
    nested.foldLeft(Map.empty[B, Map[A, C]]) { 
    case (acc, (a, innerMap)) => 
     innerMap.foldLeft(acc) { 
     case (innerAcc, (b, c)) => 
      innerAcc.updated(b, innerAcc.getOrElse(b, Map.empty).updated(a, c)) 
     } 
    } 

:

은 다른 방법은 주름의 몇 가지를 사용할 수 있습니다 (기능적으로) 외부 및 내부 맵의 키 - 값 쌍을 반복하여 결과를 구축합니다. 내 머리 꼭대기에서 좀 더 효율적이라고 생각 하겠지만, 그 점에 대해서는 잘 모르겠습니다. 그리고별로 중요하지 않으므로 개인적으로 더 명확하게 선택하는 것이 좋습니다.

-1

할 수 있습니다 단순히 주어진지도 컬렉션 맵 작업을 사용하여 수행

scala> Map("A" -> Map("B" -> "C"), "X" -> Map("Y" -> "Z")) 
res1: scala.collection.immutable.Map[String,scala.collection.immutable.Map[String,String]] = Map(A -> Map(B -> C), X -> Map(Y -> Z)) 

scala> res1.map{ case (key, valueMap) => valueMap.map{ case (vmKey, vmValue) => (vmKey -> Map(key -> vmValue)) } } 
res2: scala.collection.immutable.Iterable[scala.collection.immutable.Map[String,scala.collection.immutable.Map[String,String]]] = List(Map(B -> Map(A -> C)), Map(Y -> Map(X -> Z))) 
관련 문제