将参数列表应用于函数列表

时间:2014-08-19 14:10:38

标签: scala

我有一个参数列表,例如List(1,2,3,"abc","c")和一组函数,用于验证列表中的数据,如isNumberEvenisAValidString等。

目前,我获取列表的每个值并应用适当的函数来验证像isNumberEven(params(0))这样的数据。这导致了大而乱的代码,这在思考中是必不可少的。

我希望在Scala中可以做到这样的事情 -

List(1,2,3,"abc","c").zip(List(fuctions)).foreach{ x => x._2(x._1)}

但是,这无法给出类型不匹配的运行时异常:

  

错误:类型不匹配;   发现:x._1.type(底层类型为Any)   required:带字符串的Int

我在Function traits上尝试了模式匹配,但由于类型擦除而失败。

任何指针都将受到赞赏,如何解决这个问题。

3 个答案:

答案 0 :(得分:3)

非常天真且不可扩展的实现,我对类型不是很好,肯定有更好的方法:

val c = List(1,2,3,"abc","c")

def isEven(x: Int) = if(x % 2 == 0) true else false

def isUpperCase(x: String) = if(x.head.isUpper) true else false

c.map {
  case x: Int => isEven(x)
  case x: String => isUpperCase(x)
  case _ => false
}

您还可以定义功能列表:

scala>   val c = List(1,2,3,"abc","c")
c: List[Any] = List(1, 2, 3, abc, c)

scala>   def isEven(x: Int) = if(x % 2 == 0) true else false
isEven: (x: Int)Boolean

scala>   def isOdd(x: Int) = !isEven(x)
isOdd: (x: Int)Boolean

scala>   def isUpperCase(x: String) = if(x.head.isUpper) true else false
isUpperCase: (x: String)Boolean

scala>   def someString(x: String) = true
someString: (x: String)Boolean

scala>   val ints = List(isEven(_), isOdd(_))
ints: List[Int => Boolean] = List(<function1>, <function1>)

scala>   val strings = List(isUpperCase(_), someString(_))
strings: List[String => Boolean] = List(<function1>, <function1>)

scala>   c.map {
     |     case x: Int => ints.map(f => f(x)).exists(f => f(x))
     |     case x: String => strings.map(f => f(x)).forall(f => f(x))
     |     case _ => false
     |   }
res2: List[Boolean] = List(true, true, true, false, false)

答案 1 :(得分:2)

我只是想提出一种不匹配的不同方法,尽管它肯定是大锤。

首先,所有函数都转换为Any => Boolean类型的函数。

迭代c中的值。对于每个元素,它试图找到一个适用的函数,结果为true。如果找不到,则会产生错误。

def isEven(i: Int) = i % 2 == 0
def isGreaterThanTwo(i: Int) = i > 2
def hasB(s: String) = s.exists(_ == 'b')

def convert[T](func: T => Boolean) = (a: Any) => func(a.asInstanceOf[T])

val functions = List(isEven _, isGreaterThanTwo _, hasB _)
val c = List(1,2,3,"abc","c")

val result = {
  val convertedFunctions = functions.map(convert)

  c.map(elem => convertedFunctions.exists(func => Try(func(elem)) getOrElse false))
} 

结果为List(false, true, true, true, false)

好处是你可以拥有任意数量的功能,因此它是可扩展的。缺点是你依赖例外。 (这通常不是一个好习惯)

我首先尝试了转换为PartialFunction并修改isDefined方法的解决方案,以便在Any上调用它,然后检查某种类型。然后发生了很多类型擦除,我无法使其工作。也许这值得一试。

如果可以,可以将代码更改为:

def convert[T](func: T => Boolean) = new PartialFunction[Any, Boolean] {
  def isDefinedAt(x : Any) = ??? //check if x is an instance of T, type erasure problem
  def apply(x : Any) = func(x.asInstanceOf[T])
}

val result = {
  val convertedFunctions = functions.map(convert)

  c.map(elem => convertedFunctions.exists(func => 
  func.isDefinedAt(elem) && func(elem)))
}

看起来很不错。

答案 2 :(得分:1)

我并不完全确定您之后如何计划使用这些数据,因为&#39; foreach&#39;实际上不会返回任何东西。但也许这种模式匹配的解决方案可以帮助您实现您想要的目标吗?

scala> val f1 = (x:Int) => false
f1: Int => Boolean = <function1>

scala> val f2 = (x:String) => true
f2: String => Boolean = <function1>

scala> List(1,2,3,"abc","c").map {
    case x:String => f2(x)
    case x:Int => f1(x)
}
res3: List[Boolean] = List(false, false, false, true, true)