¿De todos modos implementa XOR en JavaScript?
-
22-09-2019 - |
Pregunta
Estoy tratando de implementar XOR en JavaScript de la siguiente manera:
// XOR validation
if ((isEmptyString(firstStr) && !isEmptyString(secondStr)) ||
(!isEmptyString(firstStr) && isEmptyString(secondStr))
{
alert(SOME_VALIDATION_MSG);
return;
}
¿Hay una mejor manera de hacer esto en JavaScript?
Gracias.
Solución
Fingido que estás buscando un Xor lógico, ya que JavaScript ya tiene uno bitwise (^) :)
Normalmente uso un operador ternario simple (una de las raras veces que uso una):
if ((isEmptyString(firstStr) ? !isEmptyString(secondStr)
: isEmptyString(secondStr))) {
alert(SOME_VALIDATION_MSG);
return;
}
Editar:
Trabajando en el @Jeff Febrero Yang solución
if ((!isEmptyString(firstStr) ^ !isEmptyString(secondStr))) {
alert(SOME_VALIDATION_MSG);
return;
}
Negas los valores para transformarlos en booleanos y luego aplica el operador XOR bitwise. Tal vez no sea tan mantenible como la primera solución (o tal vez estoy demasiado acostumbrado al primero)
Otros consejos
Como otros han señalado, Logical Xor es lo mismo que no equivalente a los booleanos, por lo que puede hacer esto:
// XOR validation
if( isEmptyString(firstStr) != isEmptyString(secondStr) )
{
alert(SOME_VALIDATION_MSG);
return;
}
Está haciendo un XOR de valores booleanos que es fácil de modelar en un XOR bitwise (que tiene JavaScript):
var a = isEmptyString(firstStr) ? 1 : 0;
var b = isEmptyString(secondStr) ? 1 : 0;
if(a ^ b) { ... }
Puede usar el operador XOR bitwise (^
) directamente:
if (isEmptyString(firstStr) ^ isEmptyString(secondStr)) {
// ...
}
Funcionará para su ejemplo desde el booleano true
y false
Los valores se convierten en 1
y 0
Porque los operadores bit a bit trabajan con enteros de 32 bits.
Esa expresión también volverá 0
o 1
, y ese valor será obligado a Boolean por el if
declaración.
Debe conocer la coerción de tipo que ocurre con el enfoque anterior, si está buscando un buen rendimiento, no le recomendaría que trabaje con los operadores bit a bit, también puede hacer una función simple para hacerlo usando solo boolean lógico lógico Operadores:
function xor(x, y) {
return (x || y) && !(x && y);
}
if (xor(isEmptyString(firstStr), isEmptyString(secondStr))) {
// ...
}
Más fácil un método:
if ((x+y) % 2) {
//statement
}
asumiendo, por supuesto, que ambas variables son verdaderos booleanos, es decir, 1
o 0
.
- Si
x === y
Obtendrá un número uniforme, por lo que Xor será0
. - Y si
x !== y
Entonces obtendrás un número impar, por lo que Xor será1
:)
Una segunda opción, si notas que x != y
evalúa como un XOR, entonces todo lo que debes hacer es
if (x != y) {
//statement
}
Que solo evaluará, nuevamente, como un XOR. (Me gusta esto mucho mejor)
Por supuesto, una buena idea sería implementar esto en una función, pero es solo su elección.
¡Espero que alguno de los dos métodos ayude a alguien! Marco esta respuesta como wiki de la comunidad, por lo que se puede mejorar.
Verificar este Explicación de diferentes implementaciones de XOR en JavaScript.
Solo para resumir algunos de ellos aquí mismo:
if( ( isEmptyString(firstStr) || isEmptyString(secondStr)) && !( isEmptyString(firstStr) && isEmptyString(secondStr)) ) {
alert(SOME_VALIDATION_MSG);
return;
}
O
if( isEmptyString(firstStr)? !isEmptyString(secondStr): isEmptyString(secondStr)) {
alert(SOME_VALIDATION_MSG);
return;
}
O
if( (isEmptyString(firstStr) ? 1 : 0 ) ^ (isEmptyString(secondStr) ? 1 : 0 ) ) {
alert(SOME_VALIDATION_MSG);
return;
}
O
if( !isEmptyString(firstStr)!= !isEmptyString(secondStr)) {
alert(SOME_VALIDATION_MSG);
return;
}
Cotizando de este artículo:
Desafortunadamente, JavaScript no tiene un operador lógico de XOR.
Puede "emular" el comportamiento del operador XOR con algo como:
if( !foo != !bar ) {
...
}
El artículo vinculado analiza un par de enfoques alternativos.
Xor solo significa "¿Son estos dos valores booleanos diferentes?". Por lo tanto:
if (!!isEmptyString(firstStr) != !!isEmptyString(secondStr)) {
// ...
}
los !!
s son solo para garantizar que el !=
El operador compara dos valores booleanos genuinos, ya que posiblemente isEmptyString()
Devuelve algo más (como null
para falso, o la cadena en sí para verdadero).
Suponiendo que está buscando el XOR booleano, aquí hay una implementación simple.
function xor(expr1, expr2){
return ((expr1 || expr2) && !(expr1 && expr2));
}
Lo anterior deriva de la definición de una "disyunción exclusiva" {cualquiera de los dos, pero no ambas}.
Dado que los valores booleanos true
y false
se convierten en 1
y 0
respectivamente, cuando se usan operadores bit a ellos, el bitwise-xor ^
Puede hacer doble servicio como un XOR lógico y un bitwiseone, siempre que sus valores sean valores booleanos (los valores "verdaderos" de JavaScript no funcionan). Esto es fácil de lograr con la negación !
operador.
a XOR b
es lógicamente equivalente a la siguiente lista (corta) de expresiones:
!a ^ !b;
!a != !b;
Hay muchas otras formas posibles, como !a ? !!b : !b
- Pero estos dos patrones tienen la ventaja de evaluar solo a
y b
Una vez cada uno (y no "cortocircuitar" también si a
es falso y, por lo tanto, no evalúa b
), mientras se forman usando ternary ?:
, O ||
, o y &&
Los operadores serán de doble evaluación o cortocircuito.
La negación !
Los operadores en ambas declaraciones es importante incluir por un par de razones: convierte todos los valores "verdaderos" en valores booleanos ("" -> falso, 12 -> verdadero, etc.) para que el operador bit a bit tenga valores con los que pueda trabajar, Entonces la desigualdad !=
El operador solo compara el valor de verdad de cada expresión (a != b
no funcionaría correctamente si a
o b
eran cadenas no igual, no vacías, etc.), y para que cada evaluación devuelva un resultado del valor booleano en lugar del primer valor "verdady".
Puede seguir expandiendo estos formularios agregando dobles negaciones (o la excepción, !!a ^ !!b
, que todavía es equivalente a XOR), pero tenga cuidado al negar solo parte de la expresión. Estas formas pueden parecer a primera vista de "trabajar" si está pensando en términos de distribución en aritmático (donde 2(a + b) == 2a + 2b
, etc.), pero de hecho produce diferentes tablas de verdad de Xor (estos producen resultados similares a Logical NXOR):
!( a ^ b )
!( !!a ^ !!b )
!!a == !!b
La forma general para Xor, entonces, podría ser la función (Videra de la mesa de la verdad):
function xor( a, b ) { return !a ^ !b; }
Y su ejemplo específico sería:
if ( xor( isEmptyString( firstStr ), isEmptyString( secondStr ) ) ) { ... }
O si isEmptyString
Devuelve solo los valores booleanos y no quieres un general xor
función, simplemente:
if ( isEmptyString( firstStr ) ^ isEmptyString( secondStr ) ) { ... }
JavaScript no tiene un operador lógico de XOR, por lo que su construcción parece plausible. Si hubieran sido números, entonces podrías haber usado ^ es decir, el operador XOR bitwise.
salud
Aquí hay un XOR que puede acomodarse de dos a muchos argumentos
function XOR() {
for (var i = 1; i < arguments.length; i++)
if ( arguments[0] != arguments[i] )
return false;
return true;
}
Ejemplo de uso:
if ( XOR( isEmptyString(firstStr), isEmptyString(secondStr) ) ) {
alert(SOME_VALIDATION_MSG);
return;
}
Espero que este sea el más corto y limpio
function xor(x,y){return true==(x!==y);}
Esto funcionará para cualquier tipo
Aquí hay una función XOR que toma un número variable de argumentos (incluidos dos). Los argumentos solo necesitan ser verdaderos o falsos, no true
o false
.
function xor() {
for (var i=arguments.length-1, trueCount=0; i>=0; --i)
if (arguments[i])
++trueCount;
return trueCount & 1;
}
En Chrome en mi MacBook 2007, se ejecuta en 14 ns para tres argumentos. Curiosamente, esta versión ligeramente diferente toma 2935 ns para tres argumentos:
function xorSlow() {
for (var i=arguments.length-1, result=false; i>=0; --i)
if (arguments[i])
result ^= true;
return result;
}
Prueba esto:
function xor(x,y)
var result = x || y
if (x === y) {
result = false
}
return result
}
Hay algunos métodos, pero el método ternario (A? Además, configurar boolean.prototype.xor parece ser una opción si necesita XOR cosas con frecuencia.
Podrías hacer esto:
Math.abs( isEmptyString(firstStr) - isEmptyString(secondStr) )
El resultado de eso es el resultado de una operación XOR.
@George, me gusta su función por su capacidad de llevar más de 2 operandos. Tengo una ligera mejora para que regrese más rápido:
function xor() {
for (var i=arguments.length-1, trueCount=0; i>=0; --i)
if (arguments[i]) {
if (trueCount)
return false
++trueCount;
}
return trueCount & 1;
}