Home > Software design >  How to implement p:A=>Boolean in Scala
How to implement p:A=>Boolean in Scala

Time:07-04

I have below HOF which takes function as an argument

def findFirst[A](ss:Array[A], p:A=>Boolean):Int ={
@tailrec
def loop(n:Int):Int ={
  if(p(ss(n))) n
  else if (n 1>=ss.length) -1
  else loop(n 1)
}
loop(0)

}

I can call the above function with the below parameters but I am wondering is there any better way to implement p?

println(findFirst(Array(6, 1,2,3,4,5,6) ,(a:Int)=> a.equals(6)))

CodePudding user response:

So only regarding the "nicer way to implement the p", and assuming your coding in Scala 2 (based on the coding style), I suggest you do this:

def findFirst[A](ss: Array[A])(p: A => Boolean): Int = ...

// And then when calling the function:
findFirst(Array(1, 2, 3, 4, 5, 6))(_ == 6)

That's because in Scala 2 type inference is done from the left-most parenthesis, so the A is inferred to be Int from the first arguments set, and you can pass the p function in a very concise manner. And also it makes more sense when you can use curried functions, doesn't it? You pass the array in the first argument set, and the function in the second one, it's like "find first elemnt in the array, that satisfies the p predicate"

CodePudding user response:

How about this?

  def findFirstIndex[A](ss: Array[A])(p: A => Boolean): Int = {
    @tailrec
    def loop(indexedArray: List[(A, Int)]): Int = indexedArray match {
      case Nil                  => -1
      case (a, n) :: xs if p(a) => n
      case _ :: xs              => loop(xs)
    }

    loop(ss.toList.zipWithIndex)
  }

I converted the array into a list into the method to have the chance to perform some structural matching using the cons operator ::. It's a common technique used in functional languages to avoid the collection index hell and all the "off by 1" bus.

Let me say that returning -1 is a bad idea; I would use an Option instead.

  def findFirstIndexSafe[A](ss: Array[A])(p: A => Boolean): Option[Int] = {
    @tailrec
    def loop(indexedArray: List[(A, Int)]): Option[Int] = indexedArray match {
      case Nil                  => None
      case (a, n) :: xs if p(a) => Some(n)
      case _ :: xs              => loop(xs)
    }

    loop(ss.toList.zipWithIndex)
  }
  • Related