Hola a todos, estoy en un problema, creo una lista de tipo string, donde guardo los simbolos matematicos, (+) (-) (*) (/), quiero usarlos para que hagan su funcion de acuerdo a lo que pido, pero no encuentro como hacerlo.
actualemnte esta asi
calculo = calculo + Convert.ToInt32(valores[i]);
pero lo necesito asi
for{ calculo = calculo ListaSimbolo[i] Convert.ToInt32(valores[i]);}
espero puedan ayudarme a resolver este problema
Los operadores no son variables.
...pero, en .NET puedes sobrecargar los operadores o definir los propios.
Podrías implementar un operador 'Operar(x,y,z)', donde uno de los parámetros fuera precisamente el operador a utilizar (basado en una enumeración), los otros parámetros serían los propios del operador.
en realidad equivaldría a una función donde pasas esos parámetros y allí mediante un 'select case' evalúa la expresión con el operador elegido.
La ventaja de definir e implementar un operador es que se puede usar de la manera concreta que precises.
No pierdas el tiempo ni reinventes la rueda, utiliza un evaluador de expresiones matemáticas. O bien eliges utilizar la función
Eval de javascript (mediante el motor de JS de .NET), o bien eliges utilizar la librería de terceros
NCalc:
- https://github.com/ncalc/ncalc
- https://github.com/ncalc/ncalc-async
Eval y
NCalc son metodologías que implican un tiempo lento de inicialización, pero ambas son robustas, a prueba de fallos. Aquí puedes ver el sofisticado procedimiento de análisis o data parsing y compilación de una expresión matemática con
NCalc: https://github.com/ncalc/.../NCalcParser (https://github.com/ncalc/ncalc/blob/master/Evaluant.Calculator/NCalcParser.cs). En general, evaluar expresiones con
NCalc es bastante más rápido que con
Eval, esto sobre todo se nota al medir el tiempo de ejecución cuando llevamos a cabo muchas operaciones de forma consecutivas en búcle, y en fin, es una solución open-source.
Ejemplo propio en VB.NET para validar sintaxis, y evaluar expresión:
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Validates the syntax of an arithmetic expression.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <example> This is a code example.
''' <code language="VB.NET">
''' Dim expr As String = "1 + ABC"
''' Dim isValid As Boolean = ValidateExpression(expr)
''' </code>
''' </example>
''' ----------------------------------------------------------------------------------------------------
''' <returns>
''' <see langword="True"/> if the arithmetic expression does not contain syntax errors,
''' otherwise, <see langword="False"/>.
''' </returns>
''' ----------------------------------------------------------------------------------------------------
<DebuggerStepThrough>
Public Shared Function ValidateExpression(expr As String) As Boolean
Dim calc As New Global.NCalc.Expression(expr)
If calc.HasErrors() Then
Return False
End If
Try
Decimal.TryParse(CStr(calc.Evaluate()), New Decimal)
Return True
Catch
Return False
End Try
End Function
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Evaluate and return the result of an arithmetic expression.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <example> This is a code example.
''' <code language="VB.NET">
''' Dim expr As String = "(1 + (2 - 2)) * (100 / 2.5)" ' = 40
''' Dim result As Decimal = EvaluateExpression(expr)
''' </code>
''' </example>
''' ----------------------------------------------------------------------------------------------------
''' <returns>
''' The resulting value.
''' </returns>
''' ----------------------------------------------------------------------------------------------------
''' <exception cref="Global.NCalc.EvaluationException">
''' </exception>
''' ----------------------------------------------------------------------------------------------------
<DebuggerStepThrough>
Public Shared Function EvaluateExpression(expr As String) As Decimal
Dim calc As New Global.NCalc.Expression(expr)
Dim result As Decimal
If calc.HasErrors() Then
Throw New Global.NCalc.EvaluationException(message:=calc.Error)
Else
Try
result = CDec(calc.Evaluate())
Return result
Catch ex As Global.NCalc.EvaluationException
Throw
Catch ex As ArgumentException
Throw New Global.NCalc.EvaluationException(message:=ex.Message)
Catch ex As Exception
Throw
End Try
End If
End Function
Importante:
NCalc no se limita solamente a evaluar expresiones de tipos numéricos, sino que además puede evaluar otros tipos como
DateTime y comparaciones de caracteres entre strings, pero las funciones
ValidateExpression y
EvaluateExpression del código de arriba funcionarán de forma correcta solamente con los tipos simples numéricos, es decir integrales o de punto flotante ( https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/value-types#built-in-value-types ) ya que es el uso que se le pretende dar.
Si prefieres hacerte el guiso por ti mismo, aquí tienes otras alternativas en C# (ordenados por fecha de antiguedad):
- https://www.codeproject.com/Articles/13779/The-expression-evaluator-revisited-Eval-function-i
- https://www.codeproject.com/Articles/46350/Evaluate-Expressions-from-C-using-javascript-s-Eva
- https://dejanstojanovic.net/aspnet/2015/january/javascript-eval-function-equivalent-in-c/
Saludos.
La solución que te ofrece Elek... digo el señor Nobody, es muy válida cuando tengas expresiones enteramente textuales, pero si el contenido procede de entresacar valores de alguna parte que vuelcas sobre un array, es preferible el método que te he descrito... también será más rápido.
Te pongo un ejemplo, tu completa, corrige allí donde precises y haz los cambios que necesites...
Primero el código de ejemplo... cuyo resultado arroja 45.
(LaClaseDondeLoPongas hace referencia a una clase donde coloques el código de la siguiente sección)
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
Dim v() As String, o() As String
Dim resultado As Single
ReDim v(0 To 4), o(0 To 4)
v(4) = "5" : v(3) = "7" : v(2) = "11" : v(1) = "13" : v(0) = "17"
o(4) = "/" : o(3) = "-" : o(2) = "+" : o(1) = "*" : o(0) = "+"
resultado = LaClaseDondeLoPongas.Operandos.Totalizar(v, o)
System.Windows.Forms.MessageBox.Show(resultado.ToString)
End Sub
Y el código que realiza todo el trabajo:
Public Structure Operandos
Public Total As Single
Private Operando As Integer
Private Operador As Operadores
Public Enum Operadores
OPERADOR_SUMA = 0
OPERADOR_RESTA = 1
OPERADOR_MULTIPLICA = 2
OPERADOR_DIVIDE = 3
End Enum
Public Shared Function Totalizar(ByRef Valores() As String, ByRef Operadores() As String) As Single
Dim k As UInt32
Dim T As New Operandos
Dim Resul As New Operandos
' NOTA: se supone que ambos arrays son igual de largos (el primer valor se considera 0, luego se entiende que el operador para el primer operando es '+').
' Procesa un operando de cada vez, con el operador asociado sobre el total acumulado
' (si entendi mal deberas corregirlo a tus necesidades)
For k = 0 To Valores.Length - 1
With T
.Operando = Convert.ToInt32(Valores(k))
.Operador = ToOperador(Operadores(k))
.Total = Resul.Total
Resul = (T = Resul)
End With
Next
Return Resul.Total
End Function
Public Shared Operator =(ByVal XY As Operandos, ByVal R As Operandos) As Operandos
With XY
Select Case .Operador
Case Operadores.OPERADOR_SUMA
Try
.Total += .Operando
Catch ex As Exception
System.Windows.Forms.MessageBox.Show(ex.Message)
End Try
Case Operadores.OPERADOR_RESTA
Try
.Total -= .Operando
Catch ex As Exception
System.Windows.Forms.MessageBox.Show(ex.Message)
End Try
Case Operadores.OPERADOR_MULTIPLICA
Try
.Total *= .Operando
Catch ex As Exception ' desbordamiento, etc...
System.Windows.Forms.MessageBox.Show(ex.Message)
End Try
Case Operadores.OPERADOR_DIVIDE
Try
.Total /= .Operando
Catch ex As Exception ' division por 0, etc...
System.Windows.Forms.MessageBox.Show(ex.Message)
End Try
End Select
Return XY
End With
End Operator
' Declarar un operador '=' exige declarar tambien otro '<>' (aunque no lo usemos).
Public Shared Operator <>(ByVal XY As Operandos, ByVal R As Operandos) As Operandos
Return Nothing
End Operator
' Resulta autoexplicativo...
Private Shared Function ToOperador(ByVal Op As String) As Operadores
Select Case Op.Trim
Case "+" : Return Operadores.OPERADOR_SUMA
Case "-" : Return Operadores.OPERADOR_RESTA
Case "*" : Return Operadores.OPERADOR_MULTIPLICA
Case "/" : Return Operadores.OPERADOR_DIVIDE
End Select
End Function
End Structure
MUCHISIMAS MUCHISIMAS GRACIAS!!! Elektro mucho tiempo sin saber de ti, q bueno estas vivo aun jeje , ya me pondre con ello de inmediato a ver como optimizar el codigo , de todos modos les compartire la solucion que encontre de momento.
for (int i = 0; i < valores.Length; i++)
{
string calc = $"{ListaSimbolos[i]}{valores[i]}";
if (calc.Contains("+"))
{
calculo = calculo + Convert.ToInt32(calc);
}
else if (calc.Contains("-"))
{
calculo = calculo + Convert.ToInt32(calc);
}
else if (calc.Contains("*"))
{
string ca = calc.Replace("*", " ").Trim();
calculo = Convert.ToInt32(calculo) * Convert.ToInt32(ca);
}
else if (calc.Contains("/"))
{
string ca = calc.Replace("/", " ").Trim();
calculo = Convert.ToInt32(calculo) / Convert.ToInt32(ca);
}
}
Explico de manera rapida, creo una lista de los signos que pido en su respectivo orden, luego obtengo cada numero y evaluo el simbolo que tiene cada valor para asi , ejecutar dicha operacion matematica, creanlo o no, me ha servido , pero si , con Ncalc simplifico esto estaria espectacular.
Nuevamente gracias y me pondre con esto. saludos a todos los q me ayudaron, gracias.
Cita de: rigorvzla en 10 Febrero 2021, 18:17 PMles compartire la solucion que encontre de momento.
Si quieres micro-optimizar ese código entonces quizás podrías tratar de aplicar el ejemplo del usuario
Serapis ya que ha invertido tiempo en hacerlo y es más completo o sofisticado que la solución actual que aplicaste, donde su ejemplo de usar Select Case / switch es más apropiado (y también más elegante, dicho sea de paso) que utilizar un bloque de condicionales else + contains ya que tienes un set de símbolos o valores fijos ( https://www.geeksforgeeks.org/switch-vs-else/ ). Además deberías intentar tener presente utilizar la asignación compuesta del operador de suma (+=) en tu variable "calculo" ( https://www.tutorialspoint.com/compound-assignment-operators-in-chash ), lo cual no optimiza el código pero simplifica bastante la comprensión del código fuente.
De todas formas a mi no me convence el enfoque que ambos le dieron, en tu caso fíjate que al final estás tratanto con varias funciones de tratamiento de cadenas de texto como string.replace y string.trim, y luego haciendo distintas operaciones sobre un mismo valor numérico, para eso sería preferible que directamente lo simplificases construyendo un string completo con la expresión matemática y pasárselo a
NCalc, pero bueno, por otro lado pienso que cualquier opción o solución es igual de válida mientras el resultado sea exitoso.
Cita de: rigorvzla en 10 Febrero 2021, 18:17 PMpero si , con Ncalc simplifico esto estaria espectacular
Poder se podría siempre y cuando le des el enfoque de construir un string / expresión matemática en lugar de hacerlo como lo estás haciendo actualmente, pero ya no merece la pena mientras tu código actual te funcione de forma exitosa no hay necesidad real de desecharlo o adaptarlo para hacer las cosas de forma distinta. Lo que yo te diría es que intentes considerar
NCalc para futuras necesidades, por que te podrá venir de perlas.
Saludos!
Yo veo un error en el "-". En los otros 3 símbolos se repiten 2 veces, pero en este caso hay un +.