2010-02-25 1 views
40

Я пытаюсь реализовать XOR в JavaScript следующим образом:Есть ли вообще реализовать XOR в JavaScript

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

Есть ли лучший способ сделать это в JavaScript?

Спасибо.

+1

Я понимаю, что это очень хороший вопрос, но я категорически не согласен с тем, что первый ответ является лучшим. Есть гораздо более простые решения, если вы прокрутите вниз ... – Nico

ответ

34

Я притворяюсь, что вы ищете логическое XOR, поскольку Javascript уже имеет побитовое один (^) :)

Я обычно использую простой тройной оператор (один из редких случаев, когда я использовать один):

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

Edit:

работает над решением @Jeff фрикадельки Ян

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

вы отрицаете значения, чтобы преобразовать их в булевы, а затем применить побитовый оператор xor.Может быть, это не так, сопровождаемым, поскольку первое решение (или, может быть, я слишком привык к первому)

+0

Спасибо, я буду использовать это предложение. – amoran

+0

Я не поймал отрицание логики OP - хороший! –

+1

Еще одна мысль: мне нравится использование побитового XOR, потому что я думаю, что тернарный оператор сложнее кого-то читать или понимать как XOR. –

5

Оформить заказ this описание различных реализаций XOR в javascript.

Просто суммировать некоторые из них прямо здесь:

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

ИЛИ

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

ИЛИ

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

ИЛИ

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

lol. 4 secs difference :) –

+0

Не могли бы вы предоставить ответы здесь, а не отталкивать пользователей от сайта, чтобы получить то, что они ищут? – Sampson

+0

@Jonathan Sampson - Я мог бы, если вы думаете, что это будет полезно. Но что именно было бы причиной для копирования кода в сообщение? Ресурс уже существует – froadie

5

Цитируя this статьи:

К сожалению, JavaScript не имеет логический оператор XOR.

Вы можете «подражать» поведение оператора XOR с чем-то вроде:

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

Связанный статье рассматривается несколько альтернативных подходов.

+3

Не могли бы вы предоставить ответы здесь, вместо того, чтобы оттолкнуть пользователей от сайта, чтобы получить то, что они ищут? – Sampson

+3

Скопируйте и вставьте? Нет. Почему бы вам не объяснить те же (или подобные) решения здесь для блага тех, кто сталкивается с этим вопросом. Если ваша связь сломалась завтра, ваш ответ не будет иметь никакой цели. – Sampson

+1

Хорошая статья. Лучший ответ - в нижней части страницы. Почему бы просто не опубликовать это с кратким объяснением? – simon

10

Вы делаете исключающее булевых значений, которое легко моделировать в побитового XOR (который Javascript имеет):

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

if(a^b) { ... } 

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

+2

+1 ... Вот как меня всегда учили делать XOR. – Robusto

+3

думая о вашем ответе ... почему бы и нет! IsEmptyString (firstStr) ^! IsEmptyString (secondStr) – Eineki

1

Javascript не имеет логического оператора XOR, так что ваши конструкция кажется правдоподобной. Если бы это были числа, вы могли бы использовать побитовый оператор XOR.

веселит

+0

Булевы принуждают к 1 и 0, как и следовало ожидать, поэтому вы можете использовать оператор XOR с булевыми. –

8

Вы можете использовать оператор поразрядное исключающее ИЛИ (^) непосредственно:

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

Он будет работать ваш пример, поскольку значения boolean true и false преобразуются в 1 и 0, потому что побитовые операторы работают с 32-битными целыми числами.

Это выражение также будет возвращено либо 0, либо 1, и это значение будет возвращено к Boolean оператором if.

Вы должны знать о типе принуждения, которое возникает при использовании вышеуказанного подхода, если вы ищете хорошую производительность, я бы не рекомендовал вам работать с побитовыми операторами, вы могли бы также сделать простую функцию для этого используя только логические логические операторы:

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


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

XOR просто означает, что «эти два булевы значения разные?». Поэтому:

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

В !! s только, чтобы гарантировать, что оператор != сравнивает два подлинных булевы значения, так как очевидно isEmptyString() возвращает что-то другое (например, null за ложь, или сама строка для истинно).

55

Как уже отмечалось, логическое XOR такое же, как не равно для булевы, так что вы можете сделать это:


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

Удивительно! На самом деле, это так просто! Почему я не слышал никого, прежде чем говорить об этом? –

+2

Это должен быть принятый ответ. * Таким образом, гораздо яснее читателю, чем прореживание с отрицаниями и побитовым xor. – jpatokal

1

вот XOR, который может вместить от двух до многих аргументов

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

Пример использования:

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

XOR применяется ко многим аргументам, определяется как true, если число аргументов нечетное, а false - иначе. Вы не можете выручить раньше. – George

0

Здесь функция исключающее ИЛИ, которая принимает переменное число аргументов (включая два). Аргументы должны быть только правдивыми или ложными, а не true или false.

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

В Chrome на моем MacBook 2007 года он работает в течение 14 нс для трех аргументов. Как ни странно, это немного другая версия имеет 2935 нс для трех аргументов:

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

Попробуйте это: function xor(x,y) var result = x || y if (x === y) { result = false } return result }

7

Легче один метод:

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

при условии, конечно, что обе переменные являются истинными булевы, то есть 1 или 0.

  • Если вы получили x === y, вы получите четное число, поэтому XOR будет 0.
  • И если x !== y тогда вы получите нечетное число, поэтому XOR будет 1 :)

Второй вариант, если вы заметили, что x != y оценивает как XOR, то все, что вы должны сделать is

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

Это будет просто оценка, опять же, как XOR. (Мне это нравится намного лучше)

Конечно, хорошая идея - реализовать это в функции, но это ваш выбор.

Надеюсь, что любой из двух методов поможет кому-то! Я отмечаю этот ответ как вики сообщества, поэтому его можно улучшить.

+0

Вы понимаете, что если оба x и y являются ложными, тогда он должен оценивать значение false вправо? x = 0 и y = 0 должны оцениваться как false, поэтому оба ваших примера НЕ являются реализацией XOR. – njfife

+0

Первое, что я не вижу, почему это неверно: false & false оценивает значение false, а true и true тоже вычисляется как false, так как оба они добавляют к кратным 2 ... И для второго: 'x! = y' оценивает только true, когда переменная истинна, а другая - нет. Даже «0! = FALSE» оценивает значение «FALSE», поэтому я не вижу вашей точки зрения, извините ... – Nico

+1

Я, честно говоря, понятия не имею, почему я подумал, что, извините, вы правы. Это краткие и чистые решения. – njfife

1

Я надеюсь, что это будет самый короткий и чистейший один

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

Это будет работать для любого типа

+0

это не то же самое, что делать: ... return (x! == y); ... '? – Nico

2

Предполагая, что вы ищете булевой XOR, вот простая реализация.

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

Приведенное выше вытекает из определения «исключительной дизъюнкции» {либо одного, но не обоих).

0

Существует несколько методов, но тройной метод (a? B: b) выглядит лучше всего. Кроме того, установка Boolean.prototype.xor представляется вариантом, если вам нужно часто выполнять xor.

http://jsperf.com/xor-implementations

0

Вы можете сделать это:

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

Результатом этого является результатом операции XOR.

2

С булевыми значениями true и false преобразуются в 1 и 0 соответственно при использовании битовых операторов на них, побитовое исключающее ИЛИ ^ могут сделать двойную обязанность как логическое XOR, а также bitwiseone, до тех пор, как ваши ценности являются логическими значениями («правдивые» значения Javascript не работают). Это легко осуществить с помощью оператора отрицания !.

a XOR b является logially эквивалентно следующему (короткий) список выражений:

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

Есть много других возможных форм - таких, как !a ? !!b : !b - но эти две модели имеют преимущество только оценки a и b один раз (и не будет «короткозамкнуто», если a является ложным и, следовательно, не оценивает b), тогда как формы с использованием тройных ?:, OR || или AND && операторы будут либо дважды оценивать, либо короткозамкнуто.

Отрицание ! операторов в обоих утверждениях важно включить по нескольким причинам: оно преобразует все «истинные» значения в логические значения («» -> false, 12 -> true и т. Д.), так что побитовый оператор имеет значения, с которыми он может работать, поэтому оператор неравенства != сравнивает только значение истинности каждого выражения (a != b не будет работать должным образом, если a или b были не равными, непустыми строками и т. д.), и поэтому что каждая оценка возвращает результат логического значения вместо первого «правдивого» значения.

Вы можете продолжать расширять эти формы, добавляя двойные отрицания (или исключение, !!a^!!b, что по-прежнему эквивалентно XOR), но будьте осторожны при отрицании только части выражения. Эти формы могут показаться на первый взгляд, «работа», если вы думаете, с точки зрения распределения в arithmatic (где 2(a + b) == 2a + 2b и т.д.), но на самом деле производят различные таблицы истинности из XOR (these produce similar results to logical NXOR):

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

общая форма XOR, то, может быть функция (truth table fiddle):

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

И ваш конкретный пример будет затем:

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

Или если isEmptyString возвращает только логические значения, и вы не хотите общую xor функции, просто:

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

@george, мне нравится ваша функция для его способности принимать более 2 операндов. У меня есть небольшое улучшение, чтобы ускорить его возвращение:

function xor() { 
    for (var i=arguments.length-1, trueCount=0; i>=0; --i) 
     if (arguments[i]) { 
      if (trueCount) 
       return false 
      ++trueCount; 
     } 
    return trueCount & 1; 
} 
Смежные вопросы