Как определить, если * точно * одно логическое значение истинно, без преобразования типа? - программирование
Подтвердить что ты не робот

Как определить, если * точно * одно логическое значение истинно, без преобразования типа?

Для произвольного списка булевых элементов, что является самым элегантным способом определения того, что именно одно из них верно?

Наиболее очевидным взломом является преобразование типов: преобразование их в 0 для false и 1 для true, а затем их суммирование и возврат sum == 1.

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

(Кажется, это должно быть тривиально, idk, длинная неделя)

Изменить: Если это не было очевидно, это скорее кодекс-гольф/теоретический вопрос. Я не суетился об использовании преобразования типа /int в коде PROD, мне просто интересно, есть ли способ сделать это без этого.

Edit2: Простите, что это долгая неделя, и я не очень хорошо объясняю себя. Позвольте мне попробовать:

В логической логике ANDing набор логических значений является истинным, если все логические значения истинны, ORing коллекция истинно, если хотя бы одно из них истинно. Есть ли логическая конструкция, которая будет истинна, если верно только одно логическое значение? XOR это для коллекции из двух булевых, например, но не более того, и она падает.
4b9b3361

Ответ 1

С простой логической логикой, возможно, не удастся добиться того, чего вы хотите. Потому что то, о чем вы просите, - это оценка истины не только по значению истины, но и по дополнительной информации (счет в этом случае). Но логическая оценка - двоичная логика, она не может зависеть ни от чего другого, кроме самих операндов. И нет никакого способа перепроектировать, чтобы найти операнды, заданные значением истины, потому что может быть четыре возможные комбинации операндов, но только два результата. Если вы ошиблись, можете ли вы сказать, связано ли это с F F F или T ^ T в вашем случае, так что следующая оценка может быть определена на основе этого?.

Ответ 2

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

В любом случае, ради удовлетворения интеллектуального любопытства, здесь идет речь. Во-первых, идея использования серии XOR хороша, но она только нас достает наполовину. Для любых двух переменных x и y,

x ⊻ y

истинно, когда только одно из них истинно. Однако это не будет продолжаться, если вы добавите третью переменную z,

x ⊻ y ⊻ z

Первая часть, x ⊻ y, по-прежнему верна, если точно одна из x и y истинна. Если x или y истинно, тогда z должно быть ложным, чтобы все выражение было истинным, и это то, что мы хотим. Но подумайте, что произойдет, если оба x и y верны. Тогда x ⊻ y является ложным, но все выражение может стать истинным, если z также истинно. Поэтому либо одна переменная, либо все три должны быть истинными. В общем случае, если у вас есть оператор, который является цепочкой XOR, он будет истинным, если истинно нечетное число переменных.

Так как одно - неравномерное число, это может оказаться полезным. Конечно, проверки на нечетное число истин недостаточно. Нам также необходимо убедиться, что не более одной переменной является истиной. Это можно сделать попарно, взяв все пары двух переменных и проверив, что они не верны. Взятые вместе эти два условия гарантируют, что точно одно, если переменные истинны.

Ниже представлен небольшой Python script, чтобы проиллюстрировать этот подход.

from itertools import product

print("x|y|z|only_one_is_true")
print("======================")
for x, y, z in product([True, False], repeat=3):
    uneven_number_is_true = x ^ y ^ z
    max_one_is_true = (not (x and y)) and (not (x and z)) and (not (y and z))
    only_one_is_true = uneven_number_is_true and max_one_is_true
    print(int(x), int(y), int(z), only_one_is_true)

А вот вывод.

x|y|z|only_one_is_true
======================
1 1 1 False
1 1 0 False
1 0 1 False
1 0 0 True
0 1 1 False
0 1 0 True
0 0 1 True
0 0 0 False

Ответ 3

После вашего разъяснения здесь он не имеет целых чисел.

 bool IsExactlyOneBooleanTrue( bool *boolAry, int size )
    {
      bool areAnyTrue = false;
      bool areTwoTrue = false;
      for(int i = 0; (!areTwoTrue) && (i < size); i++) {
        areTwoTrue = (areAnyTrue && boolAry[i]);
        areAnyTrue |= boolAry[i];
      }
      return ((areAnyTrue) && (!areTwoTrue));
    }

Ответ 4

Это можно сделать довольно хорошо с рекурсией, например. в Haskell

-- there isn't exactly one true element in the empty list
oneTrue [] = False 
-- if the list starts with False, discard it
oneTrue (False : xs) = oneTrue xs
-- if the list starts with True, all other elements must be False
oneTrue (True : xs) = not (or xs)

Ответ 5

Конечно, вы могли бы сделать что-то вроде этого (псевдокод, так как вы не указали язык):

found = false;
alreadyFound = false;
for (boolean in booleans):
    if (boolean):
        found = true;
        if (alreadyFound):
            found = false;
            break;
        else:
            alreadyFound = true;
return found;

Ответ 6

Никто не упомянул, что эта "операция", которую мы ищем, доступна с ярлыком аналогично логическим И и ИЛИ на большинстве языков. Здесь реализация в Java:

public static boolean exactlyOneOf(boolean... inputs) {
    boolean foundAtLeastOne = false;
    for (boolean bool : inputs) {
        if (bool) {
            if (foundAtLeastOne) {
                // found a second one that also true, shortcut like && and ||
                return false;
            }
            foundAtLeastOne = true;
        }
    }
    // we're happy if we found one, but if none found that less than one
    return foundAtLeastOne;
}

Ответ 7

booleanList.Where(y = > y).Count() == 1;

Ответ 8

Как вы хотите подсчитать, сколько из них истинно без, вы знаете, считаете? Конечно, вы могли бы сделать что-то грязное, как (синтаксис C, мой Python ужасен):

for(i = 0; i < last && !booleans[i]; i++)
     ;
if(i == last)
     return 0;  /* No true one found */
/* We have a true one, check there isn't another */
for(i++; i < last && !booleans[i]; i++)
     ;
if(i == last)
     return 1; /* No more true ones */
else
     return 0; /* Found another true */ 

Я уверен, вы согласитесь, что выигрыш (если есть) небольшой, а читаемость плохая.

Ответ 9

ОК, еще одна попытка. Вызовите различные булевы b[i] и вызовите их (диапазон массива) b[i .. j]. Определить функции none(b[i .. j]) и just_one(b[i .. j]) (можно заменить рекурсивные определения, чтобы получить явные формулы, если это необходимо). Мы имеем, используя обозначение C для логических операций (&& is и, || is или, ^ для xor (не на самом деле в C), ! нет):

none(b[i .. i + 1]) ~~> !b[i] && !b[i + 1]
just_one(b[i .. i + 1]) ~~> b[i] ^ b[i + 1]

И затем рекурсивно:

none(b[i .. j + 1]) ~~> none(b[i .. j]) && !b[j + 1]
just_one(b[i .. j + 1] ~~> (just_one(b[i .. j]) && !b[j + 1]) ^ (none(b[i .. j]) && b[j + 1])

И вас интересует just_one(b[1 .. n]).

Выражения будут ужасными.

Удачи!

Ответ 10

Этот python script выполняет работу красиво. Здесь используется однострочный вкладыш:

((x ∨ (y ∨ z)) ∧ (¬ (x ∧ y) ∧ (¬ (z ∧ x) ∧ ¬ (y ∧ z))))

Ответ 11

Один из способов сделать это - выполнить парный AND, а затем проверить, не возвращено ли какое-либо из парных сравнений с цепочкой OR. В python я бы использовал его с помощью

from itertools import combinations

def one_true(bools):
    pairwise_comp = [comb[0] and comb[1] for comb in combinations(bools, 2)]
    return not any(pairwise_comp)

Этот подход легко обобщается на списки произвольной длины, хотя для очень длинных списков число возможных пар растет очень быстро.

Ответ 13

Из-за большого количества чтений к этому моменту здесь происходит быстрая очистка и дополнительная информация.

Опция 1:

Спросите, истинна ли только первая переменная, или только вторая,... или только n-я переменная.

x1 & !x2 & ... & !xn |
!x1 & x2 & ... & !xn |
...
!x1 & !x2 & ... & xn

Этот подход масштабируется в O (n ^ 2), оценка останавливается после того, как найдено первое положительное совпадение. Следовательно, предпочтительнее, если есть вероятность, что есть положительное совпадение.

Вариант 2:

Спросите, есть ли хотя бы одна переменная true в общем. Дополнительно проверьте, чтобы каждая пара содержала не более одной истинной переменной (ответ Андерса Йоханнсена)

(x1 | x2 | ... | xn) &
(!x1 | !x2) &
...
(!x1 | !xn) &
(!x2 | !x3) &
...
(!x2 | !xn) &
...

Эта опция также масштабируется в O (n ^ 2) из-за количества возможных пар. Ленивая оценка останавливает формулу после первого встречного примера. Следовательно, это предпочтительно, если вероятно, что есть отрицательное совпадение.

(Вариант 3):

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

Рассматривайте x1... xn как двоичное число x. Вычтите одно, затем И результаты. Выходное значение равно нулю <=> x1... xn содержит не более одного истинного значения. (старый алгоритм "проверьте силу двух")

x    00010000
x-1  00001111
AND  00000000

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

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

Ответ 14

Почему бы просто не сделать:

count = 0
for (b in booleans):
  if (b):
     count = count + 1
return count == 1

Короткий, сладкий, никакой возможности никому не понять, что здесь происходит. И если это где-то близко к производительности, критичной для вашего приложения, у вас есть много работы, чтобы сделать реорганизацию своих вычислений и представления данных.

Ответ 15

Мы можем сделать это следующим образом: -

if (A=true or B=true)and(not(A=true and B=true)) then
<enter statements>
end if