使用 HOF 反转以 A Set 作为其值的 Map

Reverse a Map which has A Set as its value using HOF

我正在尝试反转以字符串作为键并以一组数字作为值的映射

我的目标是创建一个列表,其中包含一个数字元组和一个在值集中具有相同数字的字符串列表

到目前为止我有这个:

def flipMap(toFlip: Map[String, Set[Int]]): List[(Int, List[String])] = {
  toFlip.flatMap(_._2).map(x => (x, toFlip.keys.toList)).toList
}

但它只是将每个字符串分配给每个 Int

val map = Map(
 "A" -> Set(1,2),
 "B" -> Set(2,3)
)

应该产生: List((1, List(A)), (2, List(A, B)), (3, List(B)))

但正在生产: List((1, List(A, B)), (2, List(A, B)), (3, List(A, B)))

这有效,但它并不是您可能需要的,您可能需要进行一些转换才能获得所需的确切数据类型:

toFlip.foldLeft(Map.empty[Int, Set[String]]) {
    case (acc, (key, numbersSet)) =>
      numbersSet.foldLeft(acc) {
        (updatingMap, newNumber) =>
          updatingMap.updatedWith(newNumber) {
            case Some(existingSet) => Some(existingSet + key)
            case None => Some(Set(key))
          }
      }
  }

我使用 Set 来避免在内部列表中重复插入键,并使用 Map 来更好地查找而不是外部列表。

// both scala2 & scala3
scala> map.flatten{ case(k, s) => s.map(v => (k, v)) }.groupMapReduce{ case(k, v) => v }{case(k, v) => List(k)}{ _ ++ _ }
val res0: Map[Int, List[String]] = Map(1 -> List(A), 2 -> List(A, B), 3 -> List(B))

// scala3 only
scala> map.flatten((k, s) => s.map(v => (k, v))).groupMapReduce((k, v) => v)((k, v) => List(k))( _ ++ _ )
val res1: Map[Int, List[String]] = Map(1 -> List(A), 2 -> List(A, B), 3 -> List(B))

你可以这样做:

def flipMap(toFlip: Map[String, Set[Int]]): List[(Int, List[String])] =
  toFlip
    .toList
    .flatMap {
      case (key, values) =>
        values.map(value => value -> key)
    }.groupMap(_._1)(_._2)
    .view
    .mapValues(_.distinct)
    .toList

注意,我个人会 return Map 而不是 List


或者如果您在范围内有 cats

def flipMap(toFlip: Map[String, Set[Int]]): Map[Int, Set[String]] =
  toFlip.view.flatMap {
    case (key, values) =>
      values.map(value => Map(value -> Set(key)))
  }.toList.combineAll