Find maximum distance between elements of an array I have written a program in scala which actually does the below


  For every number between the maximum and minimum value of the array calculate the distance for each and every element in the array and find the element with maximum distance. 


I want to master functional programming in scala. Trying to understand how I can use functional programming to this.

/*
* Author: 
* Given an integer array find the distance find the index that ranges between
* minimum and maximum value of Array and that has the maximum distance from all
* the array elements. 
*/

package com.scala.practice.basic


object CycleProblem {
  def main(args: Array[String]){
    val input:Array[Int]=Array(-1000,1000,-30,70,80,20,100,110,-120,-180,120)
    val minVal=input.reduceLeft(_ min _)
    val maxVal=input.reduceLeft(_ max _)
    var maxDistance=0
    var index=minVal-1;
    for(i&lt;-minVal to maxVal){
      var distance =0
      for(j&lt;-0 to input.length-1){
        distance=distance+Math.abs(i-input(j))
      }
      if(distance &gt; maxDistance) 
        {
        maxDistance=distance
        index=i
        }
    }
    println("Park the bicycle in this location:"+ index+ " the distance(maximum when compared to to other indices) from all other parked location is: "+maxDistance + "");

  }
}
...and welcome to Scala :)

I will show changes in several steps:

a) Almost automatic changes without changing any part of the logic:

object CycleProblem extends App {
  val input: Array[Int] = Array(-1000, 1000, -30, 70, 80, 20, 100, 110, -120, -180, 120)
  val minVal = input.min
  val maxVal = input.max
  var maxDistance = 0
  var index = minVal - 1
  for (i &lt;- minVal to maxVal) {
    var distance = 0
    for (j &lt;- input.indices) {
      distance = distance + Math.abs(i - input(j))
    }
    if (distance &gt; maxDistance) {
      maxDistance = distance
      index = i
    }
  }
  println(s"Park the bicycle in this location: $index. The distance(maximum when compared to to other indices) from all other parked location is: $maxDistance")
}



Replaced the main method with extends App
Removed a couple of semicolons ;
Used string interpolation
Used plain min and max methods instead of reduce
Used .indices instead of 0 to input.length-1. You can also use the prettier 0 until input.length.


b) Important enough to get its own step: Separate your algorithm into a (stateless) function! Stateless means that the same input always produces the same output (what you intuitively expect from a function).

object CycleProblem extends App {
  val input: Array[Int] = Array(-1000, 1000, -30, 70, 80, 20, 100, 110, -120, -180, 120)

  val (index, maxDistance) = findValueInRangeWithMaxTotalDistance(input)

  println(s"Park the bicycle in this location: $index. The distance(maximum when compared to to other indices) from all other parked location is: $maxDistance")

  private def findValueInRangeWithMaxTotalDistance(input: Array[Int]): (Int, Int) = {
    val minVal = input.min
    val maxVal = input.max
    var maxDistance = 0
    var index = minVal - 1
    for (i &lt;- minVal to maxVal) {
      var distance = 0
      for (j &lt;- input.indices) {
        distance = distance + Math.abs(i - input(j))
      }
      if (distance &gt; maxDistance) {
        maxDistance = distance
        index = i
      }
    }
    (index, maxDistance)
  }
}


c) Now come the real changes: The algorithm I use is exactly the same, but expressed via functional methods on collections. You can also uncomment my println comment for check the logic of your algorithm.

object CycleProblem extends App {
  val input: Array[Int] = Array(-1000, 1000, -30, 70, 80, 20, 100, 110, -120, -180, 120)
  val (maxValue, maxDistance) = findValueInRangeWithMaxTotalDistance(input)
  println(s"Park the bicycle in this location: $maxValue. The distance(maximum when compared to to others) from all other parked location is: $maxDistance")

  def findValueInRangeWithMaxTotalDistance(input: Array[Int]): (Int, Int) = {
    def distance(a: Int, b: Int) = Math.abs(a-b)
    val valueRange = input.min to input.max
    val valuesInRangeWithTotalDistance = valueRange.map { numInRange =&gt;
      val sumOfAllDistances = input.map(itemInInput =&gt; distance(numInRange, itemInInput)).sum
      //println(s"$numInRange, $sumOfAllDistances")
      (numInRange, sumOfAllDistances)
    }
    //valuesInRangeWithTotalDistance.foreach(println)
    valuesInRangeWithTotalDistance.maxBy(_._2)//_2 is the second element, i.e. the distance
  }  
}


d) When you get accustomed to functional expressions, you can collapse the code into a few neat lines of code:

object CycleProblem extends App {
  val input: Array[Int] = Array(-1000, 1000, -30, 70, 80, 20, 100, 110, -120, -180, 120)
  val (maxValue, maxDistance) = findValueInRangeWithMaxTotalDistance(input)
  println(s"Park the bicycle in this location: $maxValue. The distance(maximum when compared to to others) from all other parked location is: $maxDistance")

  def findValueInRangeWithMaxTotalDistance(input: Array[Int]): (Int, Int) = {
    def distance(a: Int, b: Int) = Math.abs(a-b)
    val valuesInRangeWithTotalDistance = (input.min to input.max).map(numInRange =&gt; (numInRange, input.map(distance(numInRange, _)).sum))
    valuesInRangeWithTotalDistance.maxBy(_._2)
  }
}


Note my very long function name: I am reducing noisy lines of code that obscure the essence of the code (don't take it personally, it is inherent in java-like code) and add long names to describe the logic of the encapsulated algorithm.

e) To highlight my point about clarity, note that the return type of our function is (Int,Int). It is not clear what is what, lets fix it by adding a case class to hold our result:

object CycleProblem extends App {
  val input: Array[Int] = Array(-1000, 1000, -30, 70, 80, 20, 100, 110, -120, -180, 120)
  val result = findValueInRangeWithMaxTotalDistance(input)
  println(s"Park the bicycle in this location: ${result.value}. The distance(maximum when compared to to others) from all other parked location is: ${result.distance}")

  case class ValueAndDistance(value: Int, distance: Int)
  def findValueInRangeWithMaxTotalDistance(input: Array[Int]): ValueAndDistance = {
    def distance(a: Int, b: Int) = Math.abs(a-b)
    val valuesInRangeWithTotalDistance = (input.min to input.max).map(numInRange =&gt; ValueAndDistance(numInRange, input.map(distance(numInRange, _)).sum))
    valuesInRangeWithTotalDistance.maxBy(_.distance)
  }
}


Again, adding code is good, as long as it makes the logic more clear and fool-proof to your colleagues or the future-you.