XOR из трех значений
Каков самый простой способ сделать трехстороннюю эксклюзивную ИЛИ?
Другими словами, у меня есть три значения, и я хочу, чтобы оператор, который оценивает значение true IFF, имеет значение true только одно из трех значений.
До сих пор это то, что я придумал:
((a ^ b) && (a ^ c) && (b & c)) || ((b ^ a) && (b ^ c) && (a & c)) || ((c ^ a) && (c ^ b) && (a & b))
Есть ли что-то более простое, чтобы сделать то же самое?
Здесь доказательство того, что указанное выше выполняет задачу:
a = true; b = true; c = true
((a ^ b) && (a ^ c) && !(b && c)) || ((b ^ a) && (b ^ c) && !(a && c)) || ((c ^ a) && (c ^ b) && !(a && b))
=> false
a = true; b = true; c = false
((a ^ b) && (a ^ c) && !(b && c)) || ((b ^ a) && (b ^ c) && !(a && c)) || ((c ^ a) && (c ^ b) && !(a && b))
=> false
a = true; b = false; c = true
((a ^ b) && (a ^ c) && !(b && c)) || ((b ^ a) && (b ^ c) && !(a && c)) || ((c ^ a) && (c ^ b) && !(a && b))
=> false
a = true; b = false; c = false
((a ^ b) && (a ^ c) && !(b && c)) || ((b ^ a) && (b ^ c) && !(a && c)) || ((c ^ a) && (c ^ b) && !(a && b))
=> true
a = false; b = true; c = true
((a ^ b) && (a ^ c) && !(b && c)) || ((b ^ a) && (b ^ c) && !(a && c)) || ((c ^ a) && (c ^ b) && !(a && b))
=> false
a = false; b = true; c = false
((a ^ b) && (a ^ c) && !(b && c)) || ((b ^ a) && (b ^ c) && !(a && c)) || ((c ^ a) && (c ^ b) && !(a && b))
=> true
a = false; b = false; c = true
((a ^ b) && (a ^ c) && !(b && c)) || ((b ^ a) && (b ^ c) && !(a && c)) || ((c ^ a) && (c ^ b) && !(a && b))
=> true
a = false; b = false; c = false
((a ^ b) && (a ^ c) && !(b && c)) || ((b ^ a) && (b ^ c) && !(a && c)) || ((c ^ a) && (c ^ b) && !(a && b))
=> false
Ответы
Ответ 1
Для ровно трех членов вы можете использовать это выражение:
(a ^ b ^ c) && !(a && b && c)
Первая часть true
, если один или три члена являются true
. Вторая часть выражения гарантирует, что не все три true
.
Обратите внимание, что указанное выше выражение НЕ обобщает на большее количество терминов. Более общее решение состоит в том, чтобы фактически подсчитать, сколько терминов true
, так что-то вроде этого:
int trueCount =
(a ? 1 : 0) +
(b ? 1 : 0) +
(c ? 1 : 0) +
... // more terms as necessary
return (trueCount == 1); // or some range check expression etc
Ответ 2
bool result = (a?1:0)+(b?1:0)+(c?1:0) == 1;
Ответ 3
a^b^c
- только 1, если нечетное число переменных равно 1 (два '1' будут отменяться друг от друга). Поэтому вам просто нужно проверить, что "все три равны 1":
result = (a^b^c) && !(a&&b&&c)
Ответ 4
Другая возможность:
a ? !b && !c : b ^ c
который оказывается на 9 символов короче принятого ответа:)
Ответ 5
Вы также можете попробовать (в C):
!!a + !!b + !!c == 1
Ответ 6
Здесь общая реализация, которая быстро выходит из строя, когда найдено более чем bool
true
.
Использование
XOR(a, b, c);
Код
public static bool XOR(params bool[] bools)
{
return bools.Where(b => b).AssertCount(1);
}
public static bool AssertCount<T>(this IEnumerable<T> source, int countToAssert)
{
int count = 0;
foreach (var t in source)
{
if (++count > countToAssert) return false;
}
return count == countToAssert;
}
Ответ 7
f= lambda{ |a| [false, false, true].permutation.to_a.uniq.include? a }
p f.call([false, true, false])
p f.call([false, true, true])
$true
$false
Потому что я могу.
Ответ 8
Еще лучше на Python:
result = (1 if a else 0)+(1 if b else 0)+(1 if c else 0) == 1
Это также может быть использовано в операторах if!
Это спасло мой день для взаимоисключающих аргументов CLI через Click (все ненавидят click)