我正在微優化一些代碼作為挑戰。
我有一個物件串列,每個物件都有一個鍵串列。按鍵對它們進行分組的最有效方法是什么,每個物件都在它有一個鍵的每個組中。
這就是我所擁有的,但我覺得它可以改進。我有很多物件(100k ),每個物件都有~2 個鍵,并且可能的鍵少于 50 個。我嘗試將串列與 并行化listOfObjs.par,但總體上似乎沒有太大的改進。
case class Obj(value: Option[Int], key: Option[List[String]])
listOfObjs
.filter(x => x.key.isDefined && x.value.isDefined)
.flatMap(x => x.key.get.map((_, x.value.get)))
.groupBy(_._1)
uj5u.com熱心網友回復:
如果您有那么多物件,那么合乎邏輯的下一步是使用 MapReduce 框架分發作業。在一天結束時,您仍然需要檢查每個物件以確定它所屬的組,而最壞的情況將因此而成為瓶頸。
在這里你能做的最好的事情是用 a 替換這 3 個操作,fold這樣你只能迭代一次集合。
編輯:根據路易斯在評論中的建議更新了訂單
listOfObj.foldLeft(Map.empty[String, List[Int]]){ (acc, obj) =>
(obj.key, obj.value) match {
case (Some(k), Some(v)) =>
k.foldLeft(acc)((a, ky) => a (ky -> {v : a.getOrElse(ky, List.empty)}))))
case _ => acc
}
}
uj5u.com熱心網友回復:
我的印象是您正在尋找一種快速的替代方案;因此,一點點封裝的可變性會有所幫助。
那么,這樣的事情呢:
def groupObjectsByKey(objects: List[Obj]): Map[String, List[Int]] = {
val iter =
objects.iterator.flatMap {
case Obj(Some(value), Some(keys)) =>
keys.iterator.map(key => key -> value)
case _ =>
Iterator.empty[(String, Int)]
}
val m =
mutable
.Map
.empty[String, mutable.Builder[Int, List[Int]]
iter.foreach {
case (k, v) =>
m.get(key = k) match {
case Some(builder) =>
builder.addOne(v)
case None =>
m.update(key = k, value = List.newBuilder[Int].addOne(v))
}
}
immutable
.Map
.mapFactory[String, List[Int]]
.fromSpecific(m.view.mapValues(_.result()))
}
或者如果你不關心每組元素的順序,我們可以大大簡化和加速代碼:
def groupObjectsByKey(objects: List[Obj]): Map[String, List[Int]] = {
val iter = objects.iterator.flatMap {
case Obj(Some(value), Some(keys)) =>
keys.iterator.map(key => key -> value)
case _ =>
Iterator.empty[(String, Int)]
}
val m = mutable.Map.empty[String, List[Int]]
iter.foreach {
case (k, v) =>
m.updateWith(key = k) match {
case Some(list) =>
Some(v :: list)
case None =>
Some(v :: Nil)
}
}
m.to(immutable.Map)
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/327806.html
