斯卡拉最佳转向集合到一个地图,通过密钥的方式吗?斯卡拉最佳转向集合到一个地图,通过密钥的方式吗?(S

2019-05-12 20:32发布

如果我有一个集合c型的T ,有一个属性pT (类型为P ,说的),什么是做一个地图,通过提取密钥的最好方法?

val c: Collection[T]
val m: Map[P, T]

一种方法是以下几点:

m = new HashMap[P, T]
c foreach { t => m add (t.getP, t) }

但现在我需要一个可变的地图。 是否有这样做,这样它在1号线和我结束了一个不变的地图更好的办法? (很明显,我可以把上述成一个简单的库工具,因为我会在Java中,但我怀疑在Scala中没有必要)

Answer 1:

您可以使用

c map (t => t.getP -> t) toMap

但要知道,这需要2个遍历。



Answer 2:

您可以构建与元组可变数量的地图。 因此使用地图法,在收集到其转换成元组的集合,然后使用:_ *绝招结果转换成可变参数。

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)


Answer 3:

除了@詹姆斯IRY的解决方案,它也可以做到这一点使用倍。 我怀疑这种解决方案比元组方法(被创建更少垃圾对象)稍快:

val list = List("this", "maps", "string", "to", "length")
val map = list.foldLeft(Map[String, Int]()) { (m, s) => m(s) = s.length }


Answer 4:

这可以通过穿过收集折叠如下一成不变和具有单遍历实现。

val map = c.foldLeft(Map[P, T]()) { (m, t) => m + (t.getP -> t) }

解决方案的工作,因为增加的不可变映射返回与其他项新的不可变的映射,并且该值作为通过折叠操作累加器。

这里的代价是代码与效率的简单性。 因此,对于大的集合,这种方法可能比使用2个遍历实现,例如采用更合适的maptoMap



Answer 5:

另一种解决方案(可能不适用于所有类型的工作)

import scala.collection.breakOut
val m:Map[P, T] = c.map(t => (t.getP, t))(breakOut)

这就避免了创建中介名单,更多的信息在这里: 斯卡拉2.8突围



Answer 6:

什么你想实现的是一个有点不确定。
如果两个或多个项目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 }


Answer 7:

c map (_.getP) zip c

运作良好,非常intuitiv



Answer 8:

对于它的价值,这里是做两个毫无意义的方式:

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))


Answer 9:

这可能不是把一个列表映射最有效的方式,但它使调用代码更易读。 我用隐式转换到mapBy方法添加到列表:

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)

请注意,由于隐式转换,呼叫方代码需要导入Scala的implicitConversions。



Answer 10:

这对我的作品:

val personsMap = persons.foldLeft(scala.collection.mutable.Map[Int, PersonDTO]()) {
    (m, p) => m(p.id) = p; m
}

地图必须是可变的,并且地图必须是因为增加了一个可变的地图不返回地图回报。



Answer 11:

使用地图()上采集随后与toMap

val map = list.map(e => (e, e.length)).toMap


文章来源: Scala best way of turning a Collection into a Map-by-key?