Логіка перевірити, що 3 з 4 є правдою


163

Я хочу повернути Trueтоді і лише тоді, коли 3 з 4 булевих значень є істинними.

Найближче до мене (x ^ y) ^ (a ^ b):

Що я повинен зробити?


10
Хм, єдиний спосіб, який я можу придумати за допомогою математичної формули, - це використовувати кількість. Гарне питання! :)
Я Cavic

10
Ви думаєте, що це непогано, але ви повинні прийняти заперечення: not a ^ not b ^ not c ^ not dце правда, коли саме одне з заперечених значень є істинним. Це означає, що з початкових значень точно одна помилкова.
Інго

23
Яка ваша реальна проблема в основі цих деталей?
Вовк

5
@Ingo не a ^ не b ^ не c ^ не d повертає істину там, де лише одна є хибною І де 3 - хибною.
NameSpace

9
Очевидне безлічітне рішення (!a&&b&&c&&d) || (a&&!b&&c&&d) || (a&&b&&!c&&d) || (a&&b&&c&&!d).
Джейсон C

Відповіді:


248

Я пропоную написати код таким чином, що вказує на те, що ви маєте на увазі. Якщо ви хочете, щоб 3 значення були правдивими, мені здається природним, що значення 3 з'являється десь.

Наприклад, у C++:

if ((int)a + (int)b + (int)c + (int)d == 3)
    ...

Це добре визначено в C++: standard (§4.7/4)вказує на те, що перетворення boolв intдає очікувані значення 0 або 1.

У Java та C # ви можете використовувати таку конструкцію:

if ((a?1:0) + (b?1:0) + (c?1:0) + (d?1:0) == 3)
    ...

23
Це хороша відповідь. Це схоже на випадок тієї речі X / Y. "Він хоче зробити X за допомогою Y, але не знає, як це зробити Y. Замість того, щоб запитувати X, він запитує Y." Якщо він не є проектування логічної схеми або що - щось подібне (і тоді він буде в неправильному місці), кращий спосіб зробити це таким чином , що є читаним .
NothingsImpossible

2
@NothingsImpossible У цьому питанні нічого немає. Це чітке і зрозуміле питання щодо вирішення досить поширеної проблеми в програмуванні. Y не має значення.
Ярослав Рахматуллін

Дякую! Це дійсно те, що я мав намір зробити, але моя ідея була настільки незграбною, що я дотягнувся до булевої логіки.
Саймон Куанг

3
if (!!a + !!b + !!c + !!d == 3)простіше писати, хоча я не знаю, чи оптимізують це чи ні компілятори
phuclv

2
Зауважте, що в c ++ переведення від bool до int не є необхідним.
ПлазмаHH

90

№1: Використання розгалуження?: 3 або 4 операції

A ^ B ? C & D : ( C ^ D ) & A

№ 2 Нерозгалуження, 7 операцій

(A ^ B ^ C ^ D) & ((A & B) | (C & D))

Коли я використовував для профілювання всього, я виявив, що рішення, що не розгалужуються, були трохи швидшими в експлуатації, оскільки процесор міг краще передбачити шлях коду та виконувати більше операцій у тандемі. Тут десь на 50% менше роботи в заяві про розгалуження.


18
+1 - хоча інші відповіді кращі для більшості мов програмування, ваш номер 2 - найкраща відповідь у чистому булевій логіці.
Brilliand


68

Якби це був Python, я б написав

if [a, b, c, d].count(True) == 3:

Або

if [a, b, c, d].count(False) == 1:

Або

if [a, b, c, d].count(False) == True:
# In Python True == 1 and False == 0

Або

print [a, b, c, d].count(0) == 1

Або

print [a, b, c, d].count(1) == 3

Або

if a + b + c + d == 3:

Або

if sum([a, b, c, d]) == 3:

Все це працює, оскільки булеві підкласи цілих чисел у Python.

if len(filter(bool, [a, b, c, d])) == 3:

Або натхненний цим акуратним трюком ,

data = iter([a, b, c, d])
if not all(data) and all(data):

17
+1 Це вирішує проблему, правильно переклавши її на Python.
Вовк

Це трохи небезпечно, оскільки люди можуть повернути будь-яке ненульове ціле число в булевому контексті в пітоні. Старий трюк C працює і в python : a=5;not not a == 1. Недоліком є ​​відсутність справжнього булевого типу.
Во

@Voo У нас також є bool:)
thefourtheye

@thefourtheye Ах так, правда, набагато приємніше, ніж подвійний трюк / хакер заперечення.
Voo

1
Або ... або .... або .... Повинно бути один-- і бажано лише один - очевидний спосіб зробити це. : - / :-)
rz.

53

Довга, але дуже проста, (диз'юнктивна) нормальна форма:

 (~a & b & c & d) | (a & ~b & c & d) | (a & b & ~c & d) | (a & b & c & ~d)

Це може бути спрощено, але це вимагає більше мислення: P


2
@Ben, що просто надає вам різні нормальні форми, які це вже є (DNF).
Рікінг

8
Як щодо (a & b & (c ^ d)) | ((a ^ b) & c & d)?
користувач253751

2
Так, @immibis, за словами Wolfram Alpha, його DNF - це формула, яку я написав, тому це та сама булева функція.
Гастон Бенголея

2
+1, тому що я думаю, що хтось, читаючи код, зрозуміє, що намагається зробити швидше, ніж з іншими відповідями.
Болук Папукуоглу


22

Якщо ви хочете використовувати цю логіку мовою програмування, моя пропозиція така

bool test(bool a, bool b, bool c, bool d){
    int n1 = a ? 1 : 0;
    int n2 = b ? 1 : 0;
    int n3 = c ? 1 : 0;
    int n4 = d ? 1 : 0;

    return n1 + n2 + n3 + n4 == 3;
}

Або якщо ви хочете, ви можете розмістити все це в один рядок:

return (a ? 1 : 0) + (b ? 1 : 0) + (C ? 1 : 0) + (d ? 1 : 0) == 3;

Також ви можете узагальнити цю проблему для n of m :

bool test(bool *values, int n, int m){
    int sum = 0;
    for(int i = 0; i < m; i += 1){
        sum += values[i] ? 1 : 0;
    }
    return sum == n;
}

12
Бий мене до цього. Чтенність козиряє кмітливість кожного разу. +1
MikeTheLiar

20

Ця відповідь залежить від системи подання, але якщо 0 є єдиним значенням, що інтерпретується як помилкове, і not(false)завжди повертає те саме числове значення, то not(a) + not(b) + not(c) + not(d) = not(0)слід зробити фокус.


18

Маючи на увазі, що ТАК якщо на питання програмування, а не просто логічні проблеми, відповідь, очевидно, залежить від вибору мови програмування. Деякі мови підтримують функції, які рідкісні для інших.

Наприклад, на C ++ ви можете перевірити свої умови за допомогою:

(a + b + c + d) == 3

Це має бути найшвидшим способом зробити перевірку на мовах, які підтримують автоматичне (низькорівневе) перетворення з булевих у цілі типи. Але знову ж таки, загальної відповіді на цю проблему немає.


2
Це відповідь, яку я збирався опублікувати. Хоча додати одне, що залежно від мови програмування, відповідь, яку ви хочете, буде -3. В VB, True = -1.
Том Коллінз


11
((a xor b) xor (c xor d)) and ((a or b) and (c or d))

Кулак вираз шукає 1 або 3 trueз 4. Другий виключає 0 або 1 (а іноді і 2) trueз 4.


11

Java 8, відфільтруйте помилкові значення та підрахуйте інші справжні значення:

public static long count(Boolean... values) {
    return Arrays.stream(values).filter(t -> t).count();
}

Потім ви можете використовувати його наступним чином:

if (3 == count(a, b, c, d)) {
    System.out.println("There... are... THREE... lights!");
}

Легко узагальнюється перевірки nз mпунктів істинності.


11

Щоб перевірити щонайменше nз усіх Booleanправдивих, (n має бути меншим або рівним загальній кількості Boolean: p)

if (((a ? 1:0) + (b ? 1:0 ) + (c ? 1:0) + (d ? 1:0 )) >= n) {
    // do the rest
}

Редагувати : Після коментаря @ Cruncher

Для перевірки 3 booleanз 4

if (((a ? 1:0) + (b ? 1:0 ) + (c ? 1:0) + (d ? 1:0 )) == 3) {
    // do the rest
}

Інший :

((c & d) & (a ^ b)) | ((a & b) & (c ^ d))( Подробиці )


ОП хоче рівно n, не менше n. Але це легка зміна цього рішення
Cruncher

2
@Wolf це питання належить до StackUnderflow.com: p
Не помилка

10

Ось як ви могли вирішити це в C # за допомогою LINQ:

bool threeTrue = new[] { a, b, x, y }.Count(x => x) == 3;

10

Це симетрична булева функція S₃(4). Симетрична булева функція - булева функція, яка залежить тільки від кількості встановлених входів, але не залежить від того, які вони є. Кнут згадує функції цього типу в розділі 7.1.2 в томі 4 «Мистецтва комп’ютерного програмування».

S₃(4) можна обчислити за допомогою 7 операцій наступним чином:

(x && y && (a || b)) ^ ((x || y) && a && b)

Кнут показує, що це оптимально, це означає, що ви не можете зробити це менш ніж за 7 операцій, використовуючи звичайні оператори: &&, || , ^, <,і >.

Однак якщо ви хочете використовувати це мовою, яка використовує 1для істинної та 0помилкової, ви також можете легко додавати:

x + y + a + b == 3

що робить ваш намір цілком зрозумілим.


9
(a && b && (c xor d)) || (c && d && (a xor b))

З чистої логічної точки зору, це те, що я придумав.

За принципом голубої нори, якщо точно 3 істинні, то або a і b є істинним, або c і d є істинним. Тоді лише питання об'єднання кожного з цих випадків саме з одним з інших 2.

Таблиця правди Вольфрам


Це еквівалентно другому рішенню NameSpace.
Brilliand

@Brilliand мені здається іншим. Його Xors всі разом, щоб отримати всі 3 або 1, потім виключає ті, що мають 1, вимагаючи принаймні одну з 2 різних груп. (підсумовується як 1 або 3 і принаймні 2). Моє вимагає як з однієї з різних груп, так і з точністю з однієї групи.
Cruncher

Якби ви мали на увазі рівнозначне в тому сенсі, що mine <=> hisтоді я не знаю, що сказати, як цього можна було б очікувати.
Cruncher

Я думаю, я мав на увазі, що ця відповідь хороша точно так само, як і друге рішення NameSpace, не додаючи нічого нового, що відповідь NameSpace (раніше) не охоплювало. Що ж, я все-таки піднесу пропозицію.
Brilliand

8

Якщо ви використовуєте такий інструмент візуалізації логіки, як Karnaugh Maps, ви бачите, що це проблема, коли ви не можете уникнути повноцінного логічного терміна, якщо хочете записати його в одному рядку, якщо (...). Лопіна показала це вже, простіше написати це не можливо. Ви можете трохи визначити, але читати для вас І для машини буде важко.

Підрахунок рішень не є поганим, і вони показують, що ви насправді хочете. Наскільки ефективно робити підрахунок залежить від мови програмування. Рішення масивів з Python oder LinQ приємно переглядати, але будьте обережні, це ПОСЛІДНО. Wolf's (a + b + x + y) == 3 буде добре і швидко працювати, але лише якщо ваша мова порівнює "справжнє" з 1. Якщо "true" представлено -1, вам доведеться перевірити на -3: )

Якщо ваша мова використовує справжні булеви, ви можете спробувати запрограмувати це явно (я використовую! = Як тест XOR):

if (a)
{
    if (b)
        return (x != y);    // a,b=true, so either x or y must be true
    else
        return (x && y);     // a=true, b=false, so x AND y must be true
}
else
{
    if (b)
        return (x && y);    // a=false, b=true, so x and y must be true
    else
        return false;       // a,b false, can't get 3 of 4
}

"x! = y" працює лише в тому випадку, якщо x, y булевого типу. Якщо вони є якимось іншим типом, де 0 - помилково, а все інше - правда, це може не вдатися. Потім використовуйте булевий XOR або ((bool) x! = (Bool) y) або напишіть "if (x) return (y == false) else return (y == true);", що трохи більше робота за комп’ютером.

Якщо у вашій мові програмування передбачений оператор?:, Ви можете скоротити його

if (a)
    return b ? (x != y) : (x && y);
else
    return b ? (x && y) : false;

який зберігає трохи читабельності, або скорочує його агресивно

return a ? (b ? (x != y) : (x && y)) : (b ? (x && y) : false);

Цей код робить саме три логічні тести (стан a, стан b, порівняння x і y) і повинен бути швидшим, ніж більшість інших відповідей тут. Але це потрібно коментувати, інакше ви не зрозумієте це через 3 місяці :)


8

Тут є багато хороших відповідей; ось альтернативна рецептура, яку ще ніхто не опублікував:

 a ? (b ? (c ^ d) : (c && d)) : (b && c && d)

Дякую за вашу відповідь, але чи можете ви, будь ласка, додати коментар щодо того, як це працює? Дякую.
Діанна

(Вибачте за те, що я взяв участь у перегляді перевірки. Принаймні я пройшов .. :))
Діанна

7

Подібний до першої відповіді, але чистий Java:

int t(boolean b) {
    return (b) ? 1 : 0;
}

if (t(x) + t(y) + t(a) + t(b) == 3) return true;
return false;

Я вважаю за краще вважати їх цілими числами, оскільки це робить більш читабельним код.


7

У Python , щоб побачити, скільки ітерабельних елементів є True, скористайтеся sum(це досить просто):

Налаштування

import itertools

arrays = list(itertools.product(*[[True, False]]*4))

Актуальний тест

for array in arrays:
    print(array, sum(array)==3)

Вихідні дані

(True, True, True, True) False
(True, True, True, False) True
(True, True, False, True) True
(True, True, False, False) False
(True, False, True, True) True
(True, False, True, False) False
(True, False, False, True) False
(True, False, False, False) False
(False, True, True, True) True
(False, True, True, False) False
(False, True, False, True) False
(False, True, False, False) False
(False, False, True, True) False
(False, False, True, False) False
(False, False, False, True) False
(False, False, False, False) False

5

Якщо ви користуєтеся натур'янним рішенням (не програмування), то K-карти та алгоритми Quine-McCluskey - це те, що ви шукаєте, вони допоможуть вам мінімізувати булеву функцію.

У вашому випадку результат такий

y = (x̄3 ^ x2 ^ x1 ^ x0) ∨ (x3 ^ x̄2 ^ x1 ^ x0) ∨ (x3 ^ x2 ^ x̄1 ^ x0) ∨ (x3 ^ x2 ^ x1 ^ x̄0)

Якщо ви хочете зробити це програмно, нефіксованою кількістю змінних та спеціальним "порогом", то просто повторення через список булевих значень та підрахунок подій "true" є досить простим та простим.


1
Що означає планка накладних? Я помічаю його переміщення вниз по списку.
NameSpace

3
@NameSpace Це одна з IMO занадто багато позначень, які люди використовують, щоб висловити "не".

5

Я хочу повернути істину тоді і лише тоді, коли 3 з 4 булевих значень є істинними.

З огляду на 4 булевих значення, a, b, x, y, це завдання перекладається у наступне твердження C:

return (a+b+x+y) == 3;

1
Гарна пастка. Це передбачає, що trueдорівнює 1. Це неправда (не призначено каламбур) у всіх мовах / випадках. blogs.msdn.com/b/oldnewthing/archive/2004/12/22/329884.aspx
JensG

@JensG Ви маєте рацію: я роблю це припущення явним. Thx :)
Вовк

4
((a^b)^(x^y))&((a|b)&(x|y))

це те, що ти хочеш. В основному я взяв ваш код і додав перевірку, чи дійсно 3 правдиві, а не 3 - неправдиві.


4

Питання програмування без відповіді на рекурсію? Немислиме!

Є достатньо відповідей "рівно 3 з 4 прав", але ось узагальнена (Java) версія для "рівно м з n trues" (інакше рекурсія насправді не варта) тільки тому, що ви можете:

public static boolean containsTrues(boolean[] someBooleans,
    int anIndex, int truesExpected, int truesFoundSoFar) {
  if (anIndex >= someBooleans.length) {
    return truesExpected == truesFoundSoFar; // reached end
  }
  int falsesExpected = someBooleans.length - truesExpected;
  boolean currentBoolean = someBooleans[anIndex];
  int truesFound = truesFoundSoFar + (currentBoolean ? 1 : 0);
  if (truesFound > truesExpected) {
    return false;
  }
  if (anIndex - truesFound > falsesExpected) {
    return false; // too many falses
  }
  return containsTrues(someBooleans, anIndex + 1, truesExpected,
      truesFound);
}

Це можна назвати таким чином:

 boolean[] booleans = { true, false, true, true, false, true, true, false };
 containsTrues(booleans, 0, 5, 0);

який повинен повернутись true(адже 5 з 8 значень були правдивими, як і очікувалося). Не зовсім задоволений словами "trues" та "false", але не може придумати кращого імені зараз .... Зауважте, що рекурсія припиняється, коли знайдено занадто багато true або занадто багато falseзначень.


@ FélixSaparelli: Не впевнений, що "правда" застосовується тут ... звучить би так, що ти задоволений лише одним true. Можливо, щось на кшталт containsNumberOfTrueValues(). Як і в сторону: іменування Smalltalk був би набагато більш підходящим для цього, хоча: doesArray: someBooleans startingAt: anIndex containNumberOfTrueValues: anExpectedNumber foundSofar: aNumberFoundSoFar. Напевно, занадто довго для смаків деяких Java-чортів, але Smalltalkers ніколи не бояться правильного називання ;-)
Амос М. Карпентер

Це було здебільшого жартівливо. А це containsTruthозначає, що "містить деяку кількість нерозкритої кількості правди", буквально, тому я вважаю, що це цілком нормально.
Фелікс Сапареллі

3

Оскільки читабельність викликає велике занепокоєння, ви можете використовувати описовий опис функції (обгортання будь-якої із запропонованих реалізацій). Якщо цей розрахунок потрібно проводити в декількох місцях, виклик функції - найкращий спосіб досягти повторного використання і дає зрозуміти, що саме ви робите.

bool exactly_three_true_from(bool cond1, bool cond2, bool cond3, bool cond4)
{
    //...
}

3

У PHP, що робить його більш динамічним (на випадок, якщо ви зміните кількість умов тощо):

$min = 6;
$total = 10;

// create our boolean array values
$arr = array_map(function($a){return mt_rand(0,1)>0;},range(1,$total));

// the 'check'
$arrbools = array_map(function($a){return (int)$a;},$arr);
$conditionMet = array_sum($arrbools)>=$min;

echo $conditionMet ? "Passed" : "Failed";

2
(((a AND b) OR (x AND y)) AND ((a XOR b) OR (x XOR y)))

Хоча я міг показати, що це хороше рішення, відповідь Сема Хочевара легко і написати, і зрозуміти пізніше. У моїй книзі це робить краще.


1

Ось якийсь код # c, який я щойно написав, тому що ви мене надихнули:

Він бере будь-яку кількість аргументів і підкаже, чи n з них правдиві.

    static bool boolTester(int n, params bool[] values)
    {
        int sum = 0;           

        for (int i = 0; i < values.Length; i++)
        {
            if (values[i] == true)
            {
                sum += 1;
            }                
        }
        if( sum == n)
        {
            return true;
        }            
        return false;                
    }

і ви називаєте це так:

        bool a = true;
        bool b = true;
        bool c = true;
        bool d = false;            

        bool test = false;
        test = boolTester(3, a, b, c, d);

Тепер ви можете протестувати 7/9 або 15/100, як вам захочеться.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.