스칼라 컬렉션을지도로 바꾸는 가장 좋은 방법은 무엇입니까?
나는 모음이있는 경우 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를 가져와야합니다.
c map (_.getP) zip c
잘 작동하고 매우 직관적입니다
가치있는 일을 위해 여기에 무의미한 두 가지 방법이 있습니다.
scala> case class Foo(bar: Int)
defined class Foo
scala> import scalaz._, Scalaz._
import scalaz._
import Scalaz._
scala> val c = Vector(Foo(9), Foo(11))
c: scala.collection.immutable.Vector[Foo] = Vector(Foo(9), Foo(11))
scala> c.map(((_: Foo).bar) &&& identity).toMap
res30: scala.collection.immutable.Map[Int,Foo] = Map(9 -> Foo(9), 11 -> Foo(11))
scala> c.map(((_: Foo).bar) >>= (Pair.apply[Int, Foo] _).curried).toMap
res31: scala.collection.immutable.Map[Int,Foo] = Map(9 -> Foo(9), 11 -> Foo(11))
zip과 toMap을 사용하는 것은 어떻습니까?
myList.zip(myList.map(_.length)).toMap
이것은 나를 위해 작동합니다 :
val personsMap = persons.foldLeft(scala.collection.mutable.Map[Int, PersonDTO]()) {
(m, p) => m(p.id) = p; m
}
변경 가능한 맵에 추가해도 맵이 반환되지 않으므로 맵을 변경할 수 있어야하고 맵을 반환해야합니다.
toMap과 함께 컬렉션에서 map () 사용
val map = list.map(e => (e, e.length)).toMap
참고URL : https://stackoverflow.com/questions/674639/scala-best-way-of-turning-a-collection-into-a-map-by-key
'IT story' 카테고리의 다른 글
매개 변수를 사용하여 Backbone.js 페치 (0) | 2020.06.09 |
---|---|
PostgreSQL에서 그룹화 된 LIMIT : 각 그룹의 첫 N 행을 표시합니까? (0) | 2020.06.09 |
Python에서 문자열 목록에 동일한 문자열 추가 (0) | 2020.06.09 |
다른 모든 컨트롤 위에 오버레이 컨트롤을 만드는 방법은 무엇입니까? (0) | 2020.06.09 |
JavaScript가없는 기본 HTML 양식 포커스 (0) | 2020.06.09 |