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

Scala 将参数列表应用于函数列表,scala,Scala,我有一个参数列表,如list(1,2,3,“abc”,“c”)和一组验证列表中数据的函数,如isNumberEven,isAValidString等 目前,我获取列表的每个值并应用适当的函数来验证数据,如isNumberEven(params(0))。这导致了庞大而混乱的代码,这在思考中是绝对必要的 我希望在Scala中可以做类似的事情- List(1,2,3,"abc","c").zip(List(fuctions)).foreach{ x => x._2(x._1)} 但是,如果出现

我有一个参数列表,如
list(1,2,3,“abc”,“c”)
和一组验证列表中数据的函数,如
isNumberEven
isAValidString

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

我希望在Scala中可以做类似的事情-

List(1,2,3,"abc","c").zip(List(fuctions)).foreach{ x => x._2(x._1)}
但是,如果出现类型不匹配的运行时异常,则此操作失败:

错误:类型不匹配; 已找到:x._1.type(具有基础类型Any) 必需:带字符串的Int

我试着在函数特性上进行模式匹配,但由于类型擦除,它失败了


对于如何解决这一问题,任何指点都将不胜感激

我不能完全确定您以后打算如何使用这些数据,因为“foreach”实际上不会返回任何内容。但也许这种模式匹配的解决方案可以帮助你实现你想要的

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)
scala>val f1=(x:Int)=>false
f1:Int=>Boolean=
scala>valf2=(x:String)=>true
f2:String=>Boolean=
scala>列表(1,2,3,“abc”,“c”)。地图{
案例x:String=>f2(x)
案例x:Int=>f1(x)
}
res3:List[Boolean]=List(false,false,false,true,true)

非常幼稚且不可扩展的实现,我不太擅长类型,当然有更好的方法:

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)
scala>val c=List(1,2,3,“abc”,“c”)
c:List[Any]=列表(1,2,3,abc,c)
scala>def isEven(x:Int)=如果(x%2==0)为真,否则为假
isEven:(x:Int)布尔型
scala>defisodd(x:Int)=!伊塞文(x)
isOdd:(x:Int)布尔型
scala>def isUpperCase(x:String)=如果(x.head.isUpper)为真,否则为假
isUpperCase:(x:String)布尔值
scala>defsomestring(x:String)=true
someString:(x:String)布尔值
scala>val ints=List(isEven(uu),isOdd(ux))
Int:List[Int=>Boolean]=List(,)
scala>val strings=List(isUpperCase(u),someString(u))
strings:List[String=>Boolean]=List(,)
scala>c.map{
|案例x:Int=>Int.map(f=>f(x)).exists(f=>f(x))
|案例x:String=>strings.map(f=>f(x)).forall(f=>f(x))
|大小写=>false
|   }
res2:List[Boolean]=List(真、真、真、假、假)

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

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

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

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))
} 
结果
列表(false,true,true,true,false)

好处是您可以拥有任意多的功能,因此它是可扩展的。缺点是您依赖异常。(这通常不是一个好的做法)

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

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

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)))
}

这看起来很不错。

我猜OP希望传递一个函数的可变列表。因此,每个字符串可能有几个不同的验证,int等可能有几个不同的验证。嗯,您可以组合返回布尔值的函数,如
isUpperCase&!isNumeric
还是我遗漏了什么?当然可以。但是代码是不灵活的。如果您想在这段代码的一个调用上运行一组验证,在另一个调用上运行另一组验证,会发生什么?验证函数列表是实现这一点的最佳方式。@Paul是的,我理解了你的意思,我进行了编辑。好的。我不确定OP是否希望每个类型都有单独的列表(因为它不能动态扩展到其他类型),但如果不需要,而且还需要一个混合类型的值列表,那么OP也不会太在意类型检查:)您可能知道类型是一致的,但编译器不会。如果你走这条路,编译器将无法帮助你。对参数列表进行建模总是有更好的方法。谢谢,但是代码对于我的需要来说是不灵活的。比如说,我想对字符串“abc”应用f2(x),对最后一个字符串应用f3(x)。那是行不通的。我最初使用的是你的方法(尝试部分除外)。对我来说,问题在于,采用与其签名不符的参数的验证函数不应返回true或false,因为这样一来,失败的验证就等于从某个角度来看是错误的不适用的验证,它们应该有一些自定义结果,可以在之后过滤掉,因为它们返回的false与验证函数返回的false不一样。我同意这是有区别的,但OP没有规定,这就是为什么我选择简化它。