如何在Scala中计算具有两种不同数据类型的RPN表达式? [英] How to calculate a RPN expression having two different data types in Scala?
问题描述
下面的程序假设要计算一个表达式,它可能具有两种不同的数据类型Float
和RDD
.我已经从中缀表达式创建了RPN,现在我正在尝试对它们执行计算.
注意:在RDD
和float
上进行计算时,我也重载了:+,-,/,*.
The following program is suppose to calculate an expression with the possibility of having two different data types , Float
and RDD
. I already created an RPN from the infix expression and now I am trying to perform calculations on them.
Note: I have also overloaded :+,-,/,* for doing calculations on RDD
and float
.
def calcRPN(s: String): RDD[(Int,Array[Float])] =
(s.split(' ').toList.foldLeft(Nil: List[Either[Float, RDD[(Int,Array[Float])]]) {foldingFunction}).head
def foldingFunction(list: List[Either[Float, RDD[(Int,Array[Float])]]], next: String): List[Either[Float,RDD[(Int,Array[Float])]]] = (list, next) match {
//apply * on inputs
case (Right(x) :: Right(y) :: ys, "*") =>{(sv.*(x,y)) :: ys} //both RDD sv is another class containing overloads
case (Left(x) :: Right(y) :: ys, "*") =>{sv.*(x,y) :: ys} //x being float
case (Right(x) :: Left(y) :: ys, "*") =>{sv.*(x,y) :: ys} //y being float}
case (Left(x) :: Left(y) :: ys, "*") => (x * y) :: ys //both float
//apply + on inputs
case (Right(x) :: Right(y) :: ys, "+") => {(sv.+(x,y)) :: ys} //both RDD
case (Left(x) :: Right(y) :: ys, "+") =>{(sv.+(x,y)):: ys} //x being float
case (Right(x) :: Left(y) :: ys, "+") =>{(sv.+(x,y)):: ys} //y being float
case (Left(x) :: Left(y) :: ys, "+") => (y + x) :: ys //both float
//apply - on the inputs
case (Right(x) :: Right(y) :: ys, "-") => {(sv.-(x,y)):: ys} //both RDD
case (Left(x) :: Right(y) :: ys, "-") =>{(sv.-(x,y)) :: ys} //x being float
case (Right(x) :: Left(y) :: ys, "-") =>{(sv.-(x,y)):: ys} //y being float
case (Left(x) :: Left(y) :: ys, "-") => (y - x) :: ys //both float
//apply / on the inputs
case (Right(x) :: Right(y) :: ys, "/") => {(sv./(x,y)) :: ys} //both RDD
case (Left(x) :: Right(y) :: ys, "/") =>{(sv./(x,y)) :: ys} //x being float
case (Right(x) :: Left(y) :: ys, "/") =>{(sv./(x,y)):: ys} //y being float
case (Left(x) :: Left(y) :: ys, "/") => {(y / x) :: ys} //both float
case (xs, numString) => numString.toInt :: xs //**
case (xs, pathxml) => sv.getArrayRDD() :: xs //***
}
我知道这段代码很抱歉.我可以把它缩短一些,但是现在我需要使其工作,然后再刷一下!
因此,在**部分中,它适用于两个数字,但我添加了***,以使其也接受RDD
.不知道它是否对Float
和RDD
均适用!另外,由于使用Either
我遇到了以下错误,显然Left
和Right
在这里没有帮助我!
I know this code is ugly sorry about that. I can make it shorter but right now I need to make it work then brush it up!
So in the ** part it is working for two numbers but I added *** to make it accept RDD
as well. Don't know if it works for both Float
and RDD
! plus I have faced the following error because of using Either
and apparently Left
and Right
are not helping me here!
[error] type mismatch;
[error] found : Either[Float,org.apache.spark.rdd.RDD[(Int, Array[Float])]]
[error] required: org.apache.spark.rdd.RDD[(Int, Array[Float])]
[error] (s.split(' ').toList.foldLeft(Nil: List[Either[Float, RDD[(Int,Array[Float])]]]) {foldingFunction}).head
[error] ^
我也尝试过Scalaz
,但是它变得更加复杂.
I also tried Scalaz
but it made it more complex.
推荐答案
首先要确定,为了更好的理解,让我们分解一下内容:
Ok first things first, lets split up things for a better understanding:
val creepyListOfoperatorsAndStuff: List[String] = s.split(' ').toList
val eitherList: List[Either[Float, RDD[(Int,Array[Float])]]] =
creepyListOfoperatorsAndStuff.foldLeft(
List.empty[Either[Float, RDD[(Int,Array[Float])]]
) (foldingFunction)
val headEither:Either[Float, RDD[(Int,Array[Float])]] = eitherList.head
该列表的头是Either.因此,既不是Float也不是RDD. 这意味着我们必须确定它是Float还是RDD [(Int,Array [Float])]. 如果您真的确定磁头包含RDD,则可以执行以下操作:
The head of that List is an Either. Thus neither a Float nor a RDD. That means we have to decide whether it is a Float or a RDD[(Int,Array[Float])]. If you are REALLY sure head contains an RDD, you can just do:
headEither.right.get
一种更好的方法可能是处理这两种情况:
A better way to do this might be to deal with both cases:
headEither.fold[RDD[(Int,Array[Float])]](
// function to convert a Left() result to the RDD you want
fa = someFloat => <code to get to the RDD you want>,
// this is a function to transform the Right() result to what is desired
// as RDD is what you want you can just return the input
fb = anRDD => anRDD
)
现在开始处理**和***:
Now onwards to the cases ** and ***:
在
case (xs, numString) => numString.toInt :: xs //**
case (xs, pathxml) => sv.getArrayRDD() :: xs //***
第二种情况似乎无法实现,因为这两种情况都匹配相同的输入.使用正则表达式匹配您在那里期望的字符串可能会更好.我不是正则表达式匹配的专家,但是类似以下内容的内容可能会指向正确的方向.
The second case seems unreachable, because both cases match the same input. You would probably be better off using regex to match the strings you expect there. I am not exactly an expert on regular expression matching but something like the following might point in the right direction.
val Numeric = """(\d+)""".r
// don't forget to put the matched string into a group
val XmlPath = """<some regular expression that matches your expected xml path""".r
...
case (xs, NumericString(numString)) => numString.toInt :: xs //**
case (xs, XmlPath(pathxml)) => sv.getArrayRDD() :: xs //***
但是,在这两种情况下,还有一些更重要的问题:
However, there are more essential problems in theses two cases:
case (xs, numString) => numString.toInt :: xs //**
xs将是一个List [Either [Float,RDD [(Int,Array [Float])]]. 因此,我想知道,这可以编译吗?
xs would be a List[Either[Float, RDD[(Int,Array[Float])]]. Thus I have to wonder, does this compile?
numString.toInt :: xs
如果是这样,则numString.toInt可能会转换为Float,然后转换为Left [Float].但是我只是在猜测.
If so then numString.toInt is probably converted to Float and then to Left[Float]. But I'm just guessing.
case (xs, pathxml) => sv.getArrayRDD() :: xs //***
虽然我看不到 sv 可能是什么,以及它来自何处,但使用正则表达式匹配器还是可以的.
While I donn't see what sv might possibley be and where it comes form, it might be ok, with the regex matcher.
只有您提供更多信息,我才能为您提供帮助.
I would only be able to help with that with more information form you.
这篇关于如何在Scala中计算具有两种不同数据类型的RPN表达式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!