zoukankan      html  css  js  c++  java
  • Effective Scala

    本文积累一些高效的scala写法。

    Ordering

    toSeq is not good idea because driver needs to put this in memory

    .sortWith(_._2 >_._2) // short for [ (x, y) => x > y ]
    // need 2x as much memory?
    k.sortBy(x => (x._3, x._2, x._1))
    

    但是通过函数传递ordering的方式比较慢,直接Ordering.by创建内置的Ordering,或者按照下面的自定义写法更好。

    implicit def t3Ordering(implicit intOrdering: Ordering[Int]) = new Ordering[Tuple3[Int, Int, Int]] {
        def compare(x: (Int, Int, Int), y: (Int, Int, Int)): Int = {
            val compare3 = intOrdering.compare(x._3, y._3)
            if (compare3 != 0) return compare3
            val compare2 = intOrdering.compare(x._2, y._2)
            if (compare2 != 0) return compare2
            val compare1 = intOrdering.compare(x._1, y._1)
            if (compare1 != 0) return compare1
            0
        }
    }
    
    // 更标准的方式
    implicit def t3Ordering[T1, T2, T3](implicit ord1: Ordering[T1], ord2: Ordering[T2], ord3: Ordering[T3]) = new Ordering[Tuple3[T1, T2, T3]] {
      def compare(x: (T1, T2, T3), y: (T1, T2, T3)): Int = {
          val compare3 = ord3.compare(x._3, y._3)
          if (compare3 != 0) return compare3
          val compare2 = ord2.compare(x._2, y._2)
          if (compare2 != 0) return compare2
          val compare1 = ord1.compare(x._1, y._1)
          if (compare1 != 0) return compare1
          0
      }
    }
    

    参考:https://stackoverflow.com/questions/41918826/how-to-order-my-tuple-of-spark-results-descending-order-using-value
    参考: https://stackoverflow.com/questions/27659589/how-to-order-a-list-of-tuples-of-integers-in-scala

    TopN堆排

    // 方法1,静态数据
    def firstK[A](xs: Seq[A], k: Int)(implicit ord: Ordering[A]) = {
    val q = new scala.collection.mutable.PriorityQueue[A]()(ord.reverse)
    // 初始化PriorityQueue
    val (before, after) = xs.splitAt(k)
    q ++= before
     
    after.foreach(x => q += ord.max(x, q.dequeue))
    q.dequeueAll
    }
    
    // 方法1,流数据
    def firstK[A](iter: Iterator[A], k: Int)(implicit ord: Ordering[A]) = {
    val q = new scala.collection.mutable.PriorityQueue[A]()(ord.reverse)
    // 初始化PriorityQueue
    var i = k
    var flag = true
    while (flag && iter.hasNext){
     q.enqueue(iter.next())
     i -=1
     if(i == 0){
       flag = false
     }
    }
    
    iter.foreach(x => q += ord.max(x, q.dequeue))
    q.dequeueAll
    }
    
    // 方法2
    java.util.Arrays.sort(a)
    val resOfSort = a.takeRight(k).toList
    
    // 方法3,最方便,但效率最低。
    arr.sortWith(_>_).take(k) // 另外,sorted比sortWith或sortBy更快,后两个是用lambda来指示比较对象,然后才寻找隐式的,而sorted则直接用隐式或直接传入规则。
    

    测试环境基于 MBP 17 i5 下的 IDEA

    方法(Top1000) 静态数据(array) 流数据(iterator)
    Method1 1亿数据11s,1千万1s 1亿11s,1千万1秒
    Method2 1亿数据10s,1千万1s 1千万3秒
    Method3 1亿不接受,1千万7s 1千万12秒

    方法1受到Top大小影响,当数组1亿数据,k=1:2s,k=10:5s,当k=1000以上,就不及方法2了。iter方面相似。iter方面相似。这主要是因为入队过程也是要消耗时间的,如果队列一开始就已经装好了数据,那么速度还能提升。假设n为数据总量,理论上,优先队列取Topk的时间复杂度为nlogk,而k越小,效果越接近下面提到的selection algorithm,其时间复杂度为n。但是堆排的nlogn比快排的nlogn慢上不少,所以在使用dequeAll时,相当于取Topn,其效果远差于toArray后使用QuickSort。

    对于静态数据,selection algorithm可能是更好的选择,但没有现成的代码,需要自己码。有兴趣可参考leetcode215数组中的第K个最大元素

    对于流数据,方法2和3都需要把数据源进行转化,一定程度上降低了效率,而且必须把数据全部加载到内存。

    方法1参考自 https://stackoverflow.com/questions/7792189/scala-what-is-the-most-appropriate-data-structure-for-sorted-subsets/7792837#7792837

    Cut

    截取数组时用take,不用slide

    Traversal and zipWithIndex

    遍历使用while而不要用for、map、foreach等,因为virtual function calls and boxing。

    val arr = // array of ints
    val newArr = list.zipWithIndex.map { case (elem, i) =>
      if (i % 2 == 0) 0 else elem
    }
    
    // This is a high performance version of the above
    val newArr = new Array[Int](arr.length)
    var i = 0
    val len = newArr.length
    while (i < len) {
      newArr(i) = if (i % 2 == 0) 0 else arr(i)
      i += 1
    }
    

    Option and null

    如果效率非常重要,用null比option好。最好加上标记。

    class Foo {
      @javax.annotation.Nullable
      private[this] var nullableField: Bar = _
    }
    

    Scala Collection Library

    如果效率非常重要,通常Java的集合比Scala快。

    private[this]

    如果效率非常重要,可以考虑private[this]

    class MyClass {
      private val field1 = ...
      private[this] val field2 = ...
    
      def perfSensitiveMethod(): Unit = {
        var i = 0
        while (i < 1000000) {
          field1  // This might invoke a virtual method call
          field2  // This is just a field access
          i += 1
        }
      }
    }
    

    参考:https://github.com/databricks/scala-style-guide#java-type-alias

  • 相关阅读:
    css样式之补充
    css样式之属性操作
    css之操作属性
    前端基础之css样式(选择器)
    mysql之视图,触发器,事务等
    pymysql模块
    MySQL之IDE工具介绍及数据备份
    mysql老是停止运行该怎么解决
    mysql之索引原理与慢查询优化
    MySQL 5.7.9版本sql_mode=only_full_group_by问题
  • 原文地址:https://www.cnblogs.com/code2one/p/10176952.html
Copyright © 2011-2022 走看看