Phil
Phil

Reputation: 3562

Scala Generic Array Elements

I am trying to write a function that counts the number of elements in an array of elements of type T that pass a test of type T=>Boolean.

What I have so far is:

     def countPass[T](elem: Array[T]) = {
        var count = 0
        for(x <- elem) 
            x match { 
                case x: T => count += 1
            }
        count
    }

    //TEST
    println(countPass[Boolean](Array(true, 52, "test")))

I'm getting a couple of errors, the first one is:

combinators.scala:45: warning: abstract type pattern T is unchecked since
it is eliminated by erasure
                        case x: T => count += 1
                                ^

The next error is:

combinators.scala:54: error: type mismatch;
 found   : Int(52)
 required: Boolean
    println(countPass[Boolean](Array(true, 52, "test")))
                                           ^
combinators.scala:54: error: type mismatch;
 found   : String("test")
 required: Boolean
    println(countPass[Boolean](Array(true, 52, "test")))
                                               ^

I'm not sure about whats happening with the first error, but with the second error it throws an exception anytime its not a boolean. I don't want that to happen because I'm just counting the amount of elements of type T are in the array.

Question: How should I refactor my code to fix both of these errors?

Upvotes: 0

Views: 1555

Answers (3)

Mikel San Vicente
Mikel San Vicente

Reputation: 3863

You can directly use the method count

def countPass[T: ClassTag](elem: Array[Any]): Int = elem.count{
    case _ : T => true
    case _ => false
}

Upvotes: 0

Phil
Phil

Reputation: 3562

So I found out a way that works, but not exactly what I wanted.

     def countPass[T](elem: Array[T]) = {
        var count = 0
        for(x <- elem) 
            x match { 
                case _: Boolean => count += 1
                case _ => None
            }
        count
    }

    //TEST
    println(countPass[Any](Array(true, 5, "test", false, false)))

The issue was I needed to pass Any into the array because I have different types in there. Additionally, I needed to change my cases a bit and add the default case.

This works perfectly, but I wanted something more like this. This does NOT work because of the same error specified above

    def countPass[T](elem: Array[Any]) = {
        var count = 0
        for(x <- elem) 
            x match { 
                case _: T => count += 1   //Here is the error
                case _ => None
            }
        count
    }

    //TEST
    println(countPass[Boolean](Array(true, 5, "test", false, false)))

For some reason I cannot do _: T as my case or I get this error:

combinators.scala:44: warning: abstract type pattern T is unchecked since 
it is eliminated by erasure
                case _: T => count += 1

Upvotes: 0

fcat
fcat

Reputation: 1251

The trick is using ClassTag. A better way to accomplish your request is as follows:

import scala.reflect.ClassTag

object Main extends App {

  val array: Array[Any] = Array("string1", "string2", "string3", true, false, 13)

  def countPass[Other: ClassTag](array: Array[Any]): Int = {
    array.collect { case x: Other => x }.length
  }

  println(s"countPass String = ${countPass[String](array)}")
  println(s"countPass Boolean = ${countPass[Boolean](array)}")
  println(s"countPass Int = ${countPass[Int](array)}")
}

You can read this to learn more about ClassTag and TypeTag

Upvotes: 7

Related Questions