0

i am a new Scala programmer and I have a question on Scala Array pattern matching:

def countErased(sorted: Array[Array[Int]], acc: Int): Int = {
    sorted match{
        case Array() | Array(_) => acc
        case Array(h,n,_*) =>
            if(n(0) < h(1)){
                countErased(Array(h,_*), acc+1)
            }else{
                countErased(Array(n,_*), acc)
            }
    }
}

Basically what i want to do is: when we have an Array of length longer than 2, if n(0)< h(1), call function recursively with a new Array of the head and whatever as the tail. otherwise call function with a new Array of the next and whatever as the tail. But this code gets me an error:

"error: missing parameter type for expanded function ((<x$1: error>) => x$1.$times) (in solution.scala)
                countErased(Array(h,_*), acc+1)" 

What is wrong?

2
  • 1
    This is a perfect example of a situation where you should use a List instead of an Array, pattern matching has a few limitations, caused by certain implementation details and the way the type hierarchy is setup (and of course also erasure). It is possible to make this work using an alias and a type casting but it will just be very ugly. Commented Jan 2, 2021 at 15:34
  • 1
    Complementing @sinanspd this code is also pretty in efficient since Arrays are slow on all those operations, use a List instead. It would be easier, more beautiful, more efficient and safer. Commented Jan 2, 2021 at 15:44

3 Answers 3

2

Your immediate problem is addressed in the other answer: you just need to give a name to the splat, like rest@_*, and use that to refer to it.

I just want to second the advice from the comments, and mention that you should be using a List rather that an array (you can have a wrapper function that calls countErased(array.toList, 0) if that's convenient).

The match in scala also looks much nicer and idiomatic with lists:

def countErased(sorted: List[Array[Int]], acc: Int) = sorted match {
  case h@Array(_, x, _*) :: Array(y, _*) :: tail if y < x => countErased(h :: tail, acc+1) 
  case _ :: n :: tail => countErased(n :: tail, acc)
  case _ => acc
}

As a side note, one difference from your original implementation is that this one does not throw if one of the arrays happens to have fewer than two elements.

Sign up to request clarification or add additional context in comments.

Comments

2

Welcome to the Scala community :)

I concur with other comments, Seq and List tend to be recommended since they're immutable (much preferable especially in a recursive setting) and efficient.

It's doable with Array though, your code is almost working, all I had to add was giving a name to the _* capture (that's what the rest@ is doing), which is then an instance of Seq[Array], s.t. I could re-use it in the recursive call:

  def countErased(sorted: Array[Array[Int]], acc: Int): Int = {
    sorted match {
      case Array() | Array(_) => acc
      case Array(h, n, rest@_*) =>
        if (n(0) < h(1)) {
          countErased(h +: rest.toArray, acc + 1)
        } else {
          countErased(n +: rest.toArray, acc)
        }
    }
  }

Comments

1

You're actually pretty close. You just need to remember that the sorted variable is still available to you and it contains what you need to construct the next Array.

def countErased(sorted: Array[Array[Int]], acc: Int): Int =
  sorted match { 
    case Array() | Array(_) => acc
    case Array(h, n, _*) =>
      if (n(0) < h(1))  countErased(h +: sorted.drop(2), acc+1)
      else              countErased(     sorted.tail,    acc)
  }

As mentioned, it's pretty inefficient to manipulate arrays in this manner but if you're stuck with Array[Array[Int]] this will work.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.