Pergunta

Estou tentando implementar o XOR em javascript da seguinte maneira:

   // XOR validation
   if ((isEmptyString(firstStr) && !isEmptyString(secondStr)) ||
    (!isEmptyString(firstStr) && isEmptyString(secondStr))
   {
    alert(SOME_VALIDATION_MSG);
    return;
   }

Existe uma maneira melhor de fazer isso em javascript?

Obrigado.

Foi útil?

Solução

Eu finjo que você está procurando um xor lógico, já que o JavaScript já tem um bit (^) :)

Eu geralmente uso um operador ternário simples (um dos tempos raros que uso um):

if ((isEmptyString(firstStr) ? !isEmptyString(secondStr) 
                             : isEmptyString(secondStr))) {
alert(SOME_VALIDATION_MSG);
    return;
}

Editar:

Trabalhando no @Jeff Meatball Yang solução

if ((!isEmptyString(firstStr) ^ !isEmptyString(secondStr))) {
  alert(SOME_VALIDATION_MSG);
  return;
}

Você nega os valores para transformá -los em booleanos e, em seguida, aplica o operador XOR bit netwise. Talvez não seja tão sustentável quanto a primeira solução (ou talvez eu esteja muito acostumado ao primeiro)

Outras dicas

Como outros apontaram, o XOR lógico é o mesmo que não é igual para os booleanos, para que você possa fazer isso:


  // XOR validation
  if( isEmptyString(firstStr) != isEmptyString(secondStr) )
    {
      alert(SOME_VALIDATION_MSG);
      return;
    }

Você está fazendo um XOR de valores booleanos que é fácil de modelar em um XOR bit -bit (que JavaScript possui):

var a = isEmptyString(firstStr) ? 1 : 0;
var b = isEmptyString(secondStr) ? 1 : 0;

if(a ^ b) { ... }

http://www.howtocreate.co.uk/xor.html

Você pode usar o operador XOR bit netwise (^) diretamente:

if (isEmptyString(firstStr) ^ isEmptyString(secondStr)) {
  // ...
}

Funcionará para o seu exemplo desde o booleano true e false Os valores são convertidos em 1 e 0 Porque os operadores bit-bowes trabalham com números inteiros de 32 bits.

Essa expressão retornará também 0 ou 1, e esse valor será coagido de volta a Booleano pelo if declaração.

Você deve estar ciente da coerção de tipo que ocorre com a abordagem acima, se você estiver procurando um bom desempenho, eu não recomendaria que você trabalhe com os operadores bitwise, você também pode fazer uma função simples para fazer isso usando apenas lógicos booleanos operadores:

function xor(x, y) {
  return (x || y) && !(x && y);
}


if (xor(isEmptyString(firstStr), isEmptyString(secondStr))) {
  // ...
}

Um método mais fácil:

if ((x+y) % 2) {
    //statement
}

assumindo, é claro, que ambas as variáveis ​​​​são booleanas verdadeiras, ou seja, 1 ou 0.

  • Se x === y você obterá um número par, então XOR será 0.
  • E se x !== y então você obterá um número ímpar, então XOR será 1 :)

Uma segunda opção, se você perceber isso x != y avalia como um XOR, então tudo que você deve fazer é

if (x != y) {
    //statement
}

O que será avaliado, novamente, como um XOR.(Eu gosto muito mais disso)

Claro, uma boa ideia seria implementar isso em uma função, mas a escolha é apenas sua.

Espero que qualquer um dos dois métodos ajude alguém!Marco esta resposta como wiki da comunidade, para que possa ser melhorada.

Confira isto Explicação de diferentes implementações do XOR em JavaScript.

Só para resumir alguns deles aqui:

if( ( isEmptyString(firstStr) || isEmptyString(secondStr)) && !( isEmptyString(firstStr) && isEmptyString(secondStr)) ) {
   alert(SOME_VALIDATION_MSG); 
   return; 
}

OU

if( isEmptyString(firstStr)? !isEmptyString(secondStr): isEmptyString(secondStr)) {
   alert(SOME_VALIDATION_MSG); 
   return;
}

OU

if( (isEmptyString(firstStr) ? 1 : 0 ) ^ (isEmptyString(secondStr) ? 1 : 0 ) ) {
   alert(SOME_VALIDATION_MSG); 
   return;
}

OU

if( !isEmptyString(firstStr)!= !isEmptyString(secondStr)) {
   alert(SOME_VALIDATION_MSG); 
   return;
}

Citando de isto artigo:

Infelizmente, o JavaScript não possui um operador XOR lógico.

Você pode "emular" o comportamento do operador XOR com algo como:

if( !foo != !bar ) {
  ...
}

O artigo vinculado discute algumas abordagens alternativas.

XOR significa apenas "esses dois valores booleanos são diferentes?". Portanto:

if (!!isEmptyString(firstStr) != !!isEmptyString(secondStr)) {
    // ...
}

o !!s são apenas para garantir que o != O operador compara dois valores booleanos genuínos, já que é concebível isEmptyString() retorna outra coisa (como null para false, ou a própria string para verdadeiro).

Supondo que você esteja procurando o xor booleano, aqui está uma implementação simples.

function xor(expr1, expr2){
    return ((expr1 || expr2) && !(expr1 && expr2));
}

O acima deriva da definição de "disjunção exclusiva" {qualquer um, mas não ambos}.

Desde os valores booleanos true e false são convertidos para 1 e 0 respectivamente ao usar operadores bit neles, o bit-xor ^ pode fazer dupla serviço como um xor lógico e um bitweone, desde que seus valores sejam valores booleanos (os valores "verdadeiros" do JavaScript não funcionam). Isso é fácil de obter com a negação ! operador.

a XOR b é logialmente equivalente à seguinte lista (curta) de expressões:

!a ^ !b;
!a != !b;

Existem muitas outras formas possíveis - como !a ? !!b : !b - Mas esses dois padrões têm a vantagem de avaliar apenas a e b Uma vez que cada um (e não será "curto-circuito" também se a é falso e, portanto, não avaliar b), enquanto formas usando ternário ?:, OU ||, ou e && Os operadores serão avaliados duas vezes ou curto-circuito.

A negação ! Os operadores de ambas as declarações são importantes para incluir por alguns motivos: ele converte todos os valores "verdadeiros" em valores booleanos ("" -> false, 12 -> verdadeiro etc.) para que o operador bitwise tenha valores com os quais possa funcionar, Então a desigualdade != O operador compara apenas o valor da verdade de cada expressão (a != b não funcionaria corretamente se a ou b eram seqüências não iguais, não vazias, etc.), e para que cada avaliação retorne um resultado de valor booleano em vez do primeiro valor "verdadeiro".

Você pode continuar expandindo esses formulários adicionando negativas duplas (ou a exceção, !!a ^ !!b, que ainda é equivalente a XOR), mas tenha cuidado ao negar apenas parte da expressão. Essas formas podem parecer à primeira vista para "trabalhar" se você estiver pensando em termos de distribuição em aritmático (onde 2(a + b) == 2a + 2b, etc.), mas de fato produz diferentes tabelas de verdade de xor (estes produzem resultados semelhantes ao nxor lógico):

!( a ^ b )
!( !!a ^ !!b )
!!a == !!b

A forma geral para XOR, então, pode ser a função (Fiddle da mesa da verdade):

function xor( a, b ) { return !a ^ !b; }

E seu exemplo específico seria então:

if ( xor( isEmptyString( firstStr ), isEmptyString( secondStr ) ) ) { ... }

Ou se isEmptyString retorna apenas valores booleanos e você não quer um general xor função, simplesmente:

if ( isEmptyString( firstStr ) ^ isEmptyString( secondStr ) ) { ... }

O JavaScript não possui um operador XOR lógico, então seu construto parece plausível. Se tivessem sido números, você poderia ter usado ^ ou seja, o operador XOR bit.

Felicidades

Aqui está um xor que pode acomodar de dois a muitos argumentos

function XOR() {
    for (var i = 1; i < arguments.length; i++) 
        if ( arguments[0] != arguments[i] ) 
            return false; 
    return true; 
}

Exemplo de uso:

if ( XOR( isEmptyString(firstStr), isEmptyString(secondStr) ) ) {
    alert(SOME_VALIDATION_MSG);
    return;
}

Espero que este seja o mais curto e mais limpo

function xor(x,y){return true==(x!==y);}

Isso funcionará para qualquer tipo

Aqui está uma função XOR que leva um número variável de argumentos (incluindo dois). Os argumentos só precisam ser verdadeiros ou falsamente, não true ou false.

function xor() {
    for (var i=arguments.length-1, trueCount=0; i>=0; --i)
        if (arguments[i])
            ++trueCount;
    return trueCount & 1;
}

No Chrome, no meu MacBook de 2007, ele é executado em 14 ns para três argumentos. Estranhamente, esta versão ligeiramente diferente leva 2935 ns para três argumentos:

function xorSlow() {
    for (var i=arguments.length-1, result=false; i>=0; --i)
        if (arguments[i])
            result ^= true;
    return result;
}

Experimente isso: function xor(x,y) var result = x || y if (x === y) { result = false } return result }

Existem alguns métodos, mas o método ternário (a?! B: b) parece ter um desempenho melhor. Além disso, configurar boolean.prototype.xor parece ser uma opção se você precisar xorar as coisas com frequência.

http://jsperf.com/xor-implementations

Você poderia fazer isso:

Math.abs( isEmptyString(firstStr) - isEmptyString(secondStr) )

O resultado disso é o resultado de uma operação XOR.

@George, eu gosto da sua função por sua capacidade de receber mais de 2 operandos. Tenho uma ligeira melhora para fazer o retorno mais 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;
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top