【问题标题】:What is the ideal collection for incremental (with multiple passings) filtering of collection?集合的增量(多次通过)过滤的理想集合是什么?
【发布时间】:2013-12-30 22:44:09
【问题描述】:

我看到了很多关于 Scala 集合的问题,但无法做出决定。 这个question 是迄今为止最有用的。

我认为问题的核心是双重的: 1)对于这个用例,哪些是最好的集合? 2) 有哪些推荐的使用方式?

详情:

我正在实现一个迭代集合中所有元素的算法 搜索符合某个标准的那个。 搜索后,下一步是使用新标准再次搜索,但在可能性中没有选择的元素。 这个想法是创建一个序列,其中包含按标准排序的所有原始元素(在每次新选择时都会改变)。 原始序列实际上不需要排序,但可以有重复(算法一次只会选择一个)。 带有小整数序列的示例(只是为了简化):

object Foo extends App {
  def f(already_selected: Seq[Int])(element: Int): Double =
  // something more complex happens here,
  // specially something take takes 'already_selected' into account
  math.sqrt(element)

  //call to the algorithm

  val (result, ti) = Tempo.time(recur(Seq.fill(9900)(Random.nextInt), Seq()))
  println("ti = " + ti)

  //algorithm
  def recur(collection: Seq[Int], already_selected: Seq[Int]): (Seq[Int], Seq[Int]) =
     if (collection.isEmpty) (Seq(), already_selected)
     else {
        val selected = collection maxBy f(already_selected)
        val rest = collection diff Seq(selected) //this part doesn't seem to be efficient
        recur(rest, selected +: already_selected)
     }
}

object Tempo {
 def time[T](f: => T): (T, Double) = {
    val s = System.currentTimeMillis
    (f, (System.currentTimeMillis - s) / 1000d)
 }
}

【问题讨论】:

  • 据我了解 recur 不会终止
  • 完整的可编译代码添加到问题
  • 在我的测试中,Vector 和 Array 比 List 和 Seq 慢 15%。
  • @davips Seq 不是一个特定的类,它的默认实现是 List。另一方面,IndexedSeq 默认实现是 Vector。还要注意有一堆东西which complicate benchmarking of JVM code。您似乎没有考虑它们。
  • 我认为diff 在这里并不重要,因为maxBy 是一个 O(n) 操作(可能更多)。在修改旧的Seq时为了结构共享的好处,可以考虑zipWithIndex,这个解决方案:stackoverflow.com/questions/12864505/…

标签: scala scala-collections


【解决方案1】:

试试@inline 和 icn 建议的How can I idiomatically "remove" a single element from a list in Scala and close the gap?

object Foo extends App {
  @inline
  def f(already_selected: Seq[Int])(element: Int): Double =
  // something more complex happens here,
  // specially something take takes 'already_selected' into account
    math.sqrt(element)

  //call to the algorithm

  val (result, ti) = Tempo.time(recur(Seq.fill(9900)(Random.nextInt()).zipWithIndex, Seq()))
  println("ti = " + ti)

  //algorithm
  @tailrec
  def recur(collection: Seq[(Int, Int)], already_selected: Seq[Int]): Seq[Int] =
    if (collection.isEmpty) already_selected
    else {
      val (selected, i) = collection.maxBy(x => f(already_selected)(x._2))
      val rest = collection.patch(i, Nil, 1) //this part doesn't seem to be efficient
      recur(rest, selected +: already_selected)
    }
}

object Tempo {
  def time[T](f: => T): (T, Double) = {
    val s = System.currentTimeMillis
    (f, (System.currentTimeMillis - s) / 1000d)
  }
}

【讨论】:

  • 结果比原来慢了几乎两倍。我不会对其进行分析,而是将其作为建议,让事情保持简单。
  • 原版在我的机器上花了 200 多毫秒,而这个在我的机器上花了 150 毫秒。
  • 可能是JDK,我的Java版本是“1.6.0_39”。
  • java 版本 "1.7.0_45" Java(TM) SE Runtime Environment (build 1.7.0_45-b18) Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode)
猜你喜欢
  • 1970-01-01
  • 2016-02-29
  • 2022-11-23
  • 2020-10-31
  • 1970-01-01
  • 1970-01-01
  • 2011-01-20
  • 2017-02-15
  • 1970-01-01
相关资源
最近更新 更多