Why is the code written in scala 6 times slower than in java?

I am not sure if I am wrong by writing scala code.
question:

    The four adjacent digits in the 1000-digit number that have the greatest product are 9 × 9 × 8 × 9 = 5832.

    73167176531330624919225119674426574742355349194934 96983520312774506326239578318016984801869478851843 85861560789112949495459501737958331952853208805511 12540698747158523863050715693290963295227443043557 66896648950445244523161731856403098711121722383113 62229893423380308135336276614282806444486645238749 30358907296290491560440772390713810515859307960866 70172427121883998797908792274921901699720888093776 65727333001053367881220235421809751254540594752243 52584907711670556013604839586446706324415722155397 53697817977846174064955149290862569321978468622482 83972241375657056057490261407972968652414535100474 82166370484403199890008895243450658541227588666881 16427171479924442928230863465674813919123162824586 17866458359124566529476545682848912883142607690042 24219022671055626321111109370544217506941658960408 07198403850962455444362981230987879927244284909188 84580156166097919133875499200524063689912560717606 05886116467109405077541002256983155200055935729725 71636269561882670428252483600823257530420752963450

    Find the thirteen adjacent digits in the 1000-digit number that have the greatest product. What is the value of this product?  

the blogger ( http://www.ituring.com.cn/article/111574 ) says that the code he writes haskellonly accepts 6ms:

    import Data.List
    import Data.Char

    main = do
      a <- readFile "008.txt"
      print . maximum . map (product . take 13) . tails $ map digitToInt $ filter isDigit a  

so i am trying to use scala:

    object Main {

      def main(args: Array[String]): Unit = {
        val begin: Long = System.currentTimeMillis()
            val content = Source.fromFile("file/text").filter(_.isDigit).map(_.toInt - '0').toList
            val lists =
              for (i <- 0 to content.size - 13)
                yield content.drop(i).take(13)
            println(lists.maxBy(_.reduce(_ * _)))
        val end: Long = System.currentTimeMillis()
        println(end - begin)
      }
    }  

But it takes 120msan average. I thought the problem was related to I / O, but I found that it just took 10ms(I tried to use FileChannelinstead Source, but it does not save much time). These are operations mapand flatmap(for)that take up most of the time.

Then I try to use java to find out if the cause of the JVM. Not surprisingly, the java version is much faster. Just took 20ms:

    public static void main(String[] args) throws IOException {
        long begin = System.currentTimeMillis();

        byte[] bytes = Files.readAllBytes(Paths.get("file/text"));
        List<Integer> list=new ArrayList<>();
        for(int i=0;i<bytes.length;i++){
            if(bytes[i]-'0'>=0&&bytes[i]-'0'<=9) list.add(bytes[i]-'0');
        }

        int max=-1;
        List<Integer> maxList=new ArrayList<>();
        List<Integer> temp=new ArrayList<>();

        for(int i=0;i<=list.size()-13;i++){
            int value=1;
            for(int j=i;j<i+13;j++){
                temp.add(list.get(j));
                value*=list.get(j);
            }
            if(value > max) {
                max = value;
                maxList.clear();
                maxList.addAll(temp);
            }
            temp.clear();
        }
        System.out.println(maxList);
        long end = System.currentTimeMillis();
        System.out.println(end - begin);
    }  

, scala ?

+4
3

@etherous: Java-, Scala - . .

maxBy, . Java-.

val content = Source.fromFile("file/text").filter(_.isDigit).map(_.toLong - '0').toList

val result = (0 to content.size - 13).foldLeft((List.empty[Long], -1l)){case (current @(_, curMax), next) => {
    val temp = content.drop(next).take(13)
    val tempVal = temp.reduce(_*_)
    if(tempVal > curMax) (temp, tempVal) else current
  }
}

result - , _1, _2, , .

Bonus

, . sliding, . , , Scala -. , :).

content.sliding(13).maxBy(_.reduce(_*_))
+4

scala , . haskell , scala, JVM. equivilant scala , (20 , , Java):

  import scala.collection.mutable.ArrayBuffer

  val begin = System.currentTimeMillis()

  val buf = new ArrayBuffer[Int]()

  val test = "73167176531330624919225119674426574742355349194934 96983520312774506326239578318016984801869478851843 85861560789112949495459501737958331952853208805511 12540698747158523863050715693290963295227443043557 66896648950445244523161731856403098711121722383113 62229893423380308135336276614282806444486645238749 30358907296290491560440772390713810515859307960866 70172427121883998797908792274921901699720888093776 65727333001053367881220235421809751254540594752243 52584907711670556013604839586446706324415722155397 53697817977846174064955149290862569321978468622482 83972241375657056057490261407972968652414535100474 82166370484403199890008895243450658541227588666881 16427171479924442928230863465674813919123162824586 17866458359124566529476545682848912883142607690042 24219022671055626321111109370544217506941658960408 07198403850962455444362981230987879927244284909188 84580156166097919133875499200524063689912560717606 05886116467109405077541002256983155200055935729725 71636269561882670428252483600823257530420752963450"

  val d = test.toCharArray

  var i = 0
  while (i != d.length) {
    val c = d(i) - '0'
    if (c >= 0 && c <= 9) {
      buf += c
    }
    i += 1
  }


  i = 0
  var max = 0
  var maxStart = 0
  while (i != buf.length - 13) {
   val test = buf(i) * buf(i + 1) * buf(i + 2) * buf(i + 3) * buf(i +4) * buf(i + 5) * buf(i + 6) * buf(i + 7) * buf(i + 8)* buf(i + 9)* buf(i + 10)* buf(i + 11)* buf(i + 12)
   if (test > max){
      max = test
      maxStart = i
    }
    i += 1
  }


  System.out.println(buf.slice(maxStart, maxStart + 13))
  val end = System.currentTimeMillis()
  println(end - begin)

:

ArrayBuffer(9, 7, 8, 1, 7, 9, 7, 7, 8, 4, 6, 1, 7)
20

UPDATE

, JVM , 1 50 :

object Main extends App {

  (1 until 50).foreach(i => {
    val begin = System.currentTimeMillis()

    val max = Source.fromFile("file/text")
      .toList
      .filter(_.isDigit)
      .map(_.toInt - '0')
      .sliding(13)
      .maxBy(_.reduce(_ * _))

    println(max)
    val end = System.currentTimeMillis()
    println(end - begin)
  })

}

List(9, 7, 8, 1, 7, 9, 7, 7, 8, 4, 6, 1, 7)
144
...
List(9, 7, 8, 1, 7, 9, 7, 7, 8, 4, 6, 1, 7)
1
+4

Another option, just for fun. It does not convert String to Longs list at a time. 18 ms in the console.

def findMax(startTime:Long, maxStretch:List[Long], currentStretch:List[Long], longLine:String, currentProd:Long):(List[Long], Long, Long) = 
     longLine match {
     case "" => (maxStretch, maxStretch.product, System.currentTimeMillis - startTime)
     case _ => {
     val nextElement = longLine(0)
     val lastElement = currentStretch(0)
     val nextStretch = currentStretch.tail ++ List(nextElement.toLong-'0'.toLong)
     val nextProd = nextStretch.product
     val (nextMaxStretch, nextMaxProd) = if(nextProd>currentProd) {(nextStretch, nextProd)} else (maxStretch, currentProd)
     findMax(startTime,nextMaxStretch, nextStretch, longLine.substring(1),nextMaxProd)
     }
}

val strContent = <long string>.replaceAll(" ","")
val start = strContent.take(13).map(_.toLong-'0'.toLong).toList

scala> findMax(System.currentTimeMillis, start, start, strContent.drop(13), start.product)
res47: (List[Long], Long, Long) = (List(5, 5, 7, 6, 6, 8, 9, 6, 6, 4, 8, 9, 5),23514624000,18)
0
source

Source: https://habr.com/ru/post/1542731/


All Articles