나는 모음이있는 경우 c
유형을 T
하고, 등록 정보가 p
에 T
(유형 P
, 말)하는 할 수있는 가장 좋은 방법은 무엇 맵별로 추출 키는 ?
val c: Collection[T]
val m: Map[P, T]
한 가지 방법은 다음과 같습니다.
m = new HashMap[P, T]
c foreach { t => m add (t.getP, t) }
그러나 이제 변경 가능한 맵이 필요합니다 . 이 작업을 수행하는 더 좋은 방법이 있습니까? 한 줄에 있고 불변의 맵으로 끝납니다 . (Java에서와 마찬가지로 위의 내용을 간단한 라이브러리 유틸리티로 바꿀 수는 있지만 Scala에서는 필요가 없다고 생각합니다)
답변
당신이 사용할 수있는
c map (t => t.getP -> t) toMap
그러나이 과정에는 2 개의 순회가 필요합니다.
답변
가변 개수의 튜플로 맵을 구성 할 수 있습니다. 따라서 컬렉션에서 map 메소드를 사용하여 튜플 컬렉션으로 변환 한 다음 : _ * 트릭을 사용하여 결과를 변수 인수로 변환하십시오.
scala> val list = List("this", "maps", "string", "to", "length") map {s => (s, s.length)}
list: List[(java.lang.String, Int)] = List((this,4), (maps,4), (string,6), (to,2), (length,6))
scala> val list = List("this", "is", "a", "bunch", "of", "strings")
list: List[java.lang.String] = List(this, is, a, bunch, of, strings)
scala> val string2Length = Map(list map {s => (s, s.length)} : _*)
string2Length: scala.collection.immutable.Map[java.lang.String,Int] = Map(strings -> 7, of -> 2, bunch -> 5, a -> 1, is -> 2, this -> 4)
답변
@James Iry의 솔루션 외에도 접기를 사용하여이 작업을 수행 할 수도 있습니다. 이 솔루션이 튜플 방법보다 약간 빠르다고 생각합니다 (쓰레기 객체가 적습니다).
val list = List("this", "maps", "string", "to", "length")
val map = list.foldLeft(Map[String, Int]()) { (m, s) => m(s) = s.length }
답변
이것은 다음과 같이 컬렉션을 통해 접음으로써 불변 적으로 단일 순회로 구현 될 수 있습니다.
val map = c.foldLeft(Map[P, T]()) { (m, t) => m + (t.getP -> t) }
불변 맵에 추가하면 추가 항목이있는 새로운 불변 맵이 반환되고이 값은 접기 작업을 통해 누산기 역할을하기 때문에 솔루션이 작동합니다.
여기서의 단점은 코드의 단순성 대 효율성입니다. 따라서 대규모 콜렉션의 경우이 방법은 map
및 적용 과 같은 2 개의 순회 구현을 사용하는 것보다 더 적합 할 수 있습니다 toMap
.
답변
다른 솔루션 (일부 유형에서는 작동하지 않을 수 있음)
import scala.collection.breakOut
val m:Map[P, T] = c.map(t => (t.getP, t))(breakOut)
이것은 중개자 목록의 생성을 피합니다. 자세한 정보는 여기 :
Scala 2.8 breakOut
답변
당신이 달성하려는 것은 약간 정의되지 않은 것입니다.
두 개 이상의 항목 c
이 동일한 것을 공유하면 p
어떻게됩니까? p
지도에서 어떤 항목이 해당 항목에 매핑 됩니까?
이것을보다 정확하게 보는 방법 은 그것을 가진 p
모든 c
항목과 그 사이에 맵을 생성하는 것입니다.
val m: Map[P, Collection[T]]
이것은 groupBy 로 쉽게 달성 할 수 있습니다 .
val m: Map[P, Collection[T]] = c.groupBy(t => t.p)
원래지도를 계속 원한다면 예를 들어 p
첫 번째 지도 를 매핑 할 수 있습니다 t
.
val m: Map[P, T] = c.groupBy(t => t.p) map { case (p, ts) => p -> ts.head }
답변
이것은 목록을 맵으로 전환하는 가장 효율적인 방법은 아니지만 호출 코드를 더 읽기 쉽게 만듭니다. 암시 적 변환을 사용하여 mapBy 메소드를 List 에 추가했습니다 .
implicit def list2ListWithMapBy[T](list: List[T]): ListWithMapBy[T] = {
new ListWithMapBy(list)
}
class ListWithMapBy[V](list: List[V]){
def mapBy[K](keyFunc: V => K) = {
list.map(a => keyFunc(a) -> a).toMap
}
}
호출 코드 예 :
val list = List("A", "AA", "AAA")
list.mapBy(_.length) //Map(1 -> A, 2 -> AA, 3 -> AAA)
암시 적 변환으로 인해 호출자 코드는 스칼라의 implicitConversions를 가져와야합니다.