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没有规定,这就是为什么我选择简化它。