Logica per testare che 3 su 4 sono True


163

voglio ritornare True se e solo se 3 valori booleani su 4 sono veri.

Il più vicino che ho ottenuto è (x ^ y) ^ (a ^ b):

Cosa dovrei fare?


10
Hmm, l'unico modo a cui riesco a pensare senza una formula matematica è usare il conteggio. Buona domanda! :)
Sono Cavic,

10
La tua idea non è male, ma devi prendere le negazioni: not a ^ not b ^ not c ^ not dè vera quando esattamente uno dei valori negati è vera. Ciò significa che, dai valori originali, esattamente uno era falso.
Ingo,

23
Qual è il tuo vero problema dietro questi dettagli?
Wolf

5
@Ingo not a ^ not b ^ not c ^ not d restituisce vero dove solo uno è falso E dove 3 sono falsi.
NameSpace

9
L'ovvia soluzione non-count è (!a&&b&&c&&d) || (a&&!b&&c&&d) || (a&&b&&!c&&d) || (a&&b&&c&&!d).
Jason C

Risposte:


248

Suggerisco di scrivere il codice in un modo che indichi cosa intendi. Se vuoi che 3 valori siano veri, mi sembra naturale che il valore 3 appaia da qualche parte.

Ad esempio, in C++:

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

Questo è ben definito in C++: standard (§4.7/4)indica che la conversione boolin intdà i valori previsti 0 o 1.

In Java e C #, è possibile utilizzare il seguente costrutto:

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

23
Questa è una buona risposta Questo sembra un caso di quella cosa X / Y. "Vuole fare X usando Y, ma non sa come fare Y. Invece di chiedere a X, chiede a Y." A meno che non stia progettando un circuito logico o qualcosa del genere (e quindi sarebbe nel sito sbagliato), il modo migliore per farlo è in un modo leggibile .
NothingsImpossible

2
@NothingsImpossible Non c'è nulla di XY nella domanda. È una domanda chiara e diretta sulla risoluzione di un problema ragionevolmente comune nella programmazione. La Y è irrilevante.
Ярослав Рахматуллин

Grazie! Questo è davvero ciò che intendevo fare, ma la mia idea era così goffa che ho raggiunto la logica booleana.
Simon Kuang

3
if (!!a + !!b + !!c + !!d == 3)è più facile da scrivere, anche se non so se i compilatori lo ottimizzino o no
phuclv

2
Si noti che in c ++ il cast da bool a int non è necessario.
PlasmaHH,

90

# 1: Usando una ramificazione?: 3 o 4 operazioni

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

# 2 Non ramificato, 7 operazioni

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

Quando usavo per profilare tutto, ho scoperto che le soluzioni non ramificate erano un po 'più veloci operazione-per-operazione poiché la CPU poteva prevedere meglio il percorso del codice ed eseguire più operazioni in tandem. Tuttavia, nella dichiarazione di diramazione qui c'è circa il 50% di lavoro in meno.


18
+1: mentre le altre risposte sono migliori per la maggior parte dei linguaggi di programmazione, il tuo numero 2 è la risposta migliore nella pura logica booleana.
Brilliand


68

Se questo fosse stato Python, avrei scritto

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

O

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

O

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

O

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

O

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

O

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

O

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

Tutto questo funziona, poiché i booleani sono sottoclassi di numeri interi in Python.

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

O, ispirato a questo trucco pulito ,

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

17
+1 Questo risolve il problema traducendolo correttamente in Python.
Wolf

Questo è leggermente pericoloso perché le persone possono restituire qualsiasi numero intero diverso da zero in un contesto booleano in Python. Il vecchio C trucco funziona in python troppo: a=5;not not a == 1. Lo svantaggio di non avere un vero tipo booleano.
Voo

@Voo Abbiamo anche bool:)
thefourtheye

@thefourtheye Ah sì vero, molto più bello del doppio trucco / hack di negazione.
Voo

1
O ... o .... o .... Dovrebbe esserci uno - e preferibilmente solo un - modo obsoleto di farlo. : - / :-)
rz.

53

Forma normale lunga ma molto semplice (disgiuntiva):

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

Può essere semplificato, ma ciò richiede una maggiore riflessione: P


2
@Ben che ti dà solo varie forme normali di esso, che questo è già in (DNF).
Riking

8
Che ne dici (a & b & (c ^ d)) | ((a ^ b) & c & d)?
user253751

2
Sì, @immibis, secondo Wolfram Alpha il suo DNF è la formula che ho scritto, quindi è la stessa funzione booleana.
Gastón Bengolea

2
+1 perché penso che qualcuno che legge il codice capirà cosa viene tentato più rapidamente rispetto ad altre risposte.
Boluc Papuccuoglu,


22

Se vuoi usare questa logica in un linguaggio di programmazione, il mio suggerimento è

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;
}

O se vuoi, puoi mettere tutti questi in una sola riga:

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

Inoltre puoi generalizzare questo problema a 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
Battimi. La leggibilità supera ogni volta l'intelligenza. +1
MikeTheLiar

20

Questa risposta dipende dal sistema di rappresentazione, ma se 0 è l'unico valore interpretato come falso e not(false)restituisce sempre lo stesso valore numerico, allora not(a) + not(b) + not(c) + not(d) = not(0)dovrebbe fare il trucco.


18

Tenendo presente che SO se per domande di programmazione, piuttosto che semplici problemi logici, la risposta dipende ovviamente dalla scelta di un linguaggio di programmazione. Alcune lingue supportano funzionalità non comuni ad altre.

Ad esempio, in C ++ puoi testare le tue condizioni con:

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

Questo dovrebbe essere il modo più veloce per eseguire il check in lingue che supportano la conversione automatica (di basso livello) da tipi booleani a interi. Ma ancora una volta, non esiste una risposta generale a questo problema.


2
Questa è la risposta che stavo per pubblicare. Una cosa da aggiungere, tuttavia, a seconda del linguaggio di programmazione utilizzato, la risposta desiderata sarebbe -3. In VB, True = -1.
Tom Collins,


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

L'espressione del pugno cerca 1 o 3 truedi 4. Il secondo elimina 0 o 1 (e talvolta 2) truedi 4.


11

Java 8, filtra i valori falsi e conta i valori veri rimanenti:

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

Quindi puoi usarlo come segue:

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

Si generalizza facilmente al controllo della presenza ndi moggetti veri.


11

Per verificare almeno nche tutto Booleansia vero, (n deve essere minore o uguale al numero totale di Boolean: p)

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

Modifica : dopo il commento di @ Cruncher

Per controllare 3 booleansu 4

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

Un altro :

((c & d) & (a ^ b)) | ((a & b) & (c ^ d))( Dettagli )


OP vuole esattamente n, non almeno n. Ma questo è un semplice cambiamento rispetto a questa soluzione
Cruncher

2
@ Lupo che la domanda appartiene a StackUnderflow.com: p
Non un bug

10

Ecco un modo per risolverlo in C # con LINQ:

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

10

Questa è la funzione booleana simmetrica S₃(4). Una funzione booleana simmetrica è una funzione booleana che dipende solo dalla quantità di input impostati, ma non dipende da quali input siano. Knuth menziona funzioni di questo tipo nella sezione 7.1.2 del volume 4 di The Art of Computer Programming.

S₃(4) può essere calcolato con 7 operazioni come segue:

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

Knuth mostra che questo è ottimale, il che significa che non è possibile farlo in meno di 7 operazioni usando i normali operatori: &&, || , ^, <,e> .

Tuttavia, se si desidera utilizzare questo in una lingua che utilizza 1per true e 0per false, è anche possibile utilizzare l'aggiunta facilmente:

x + y + a + b == 3

che rende abbastanza chiara la tua intenzione.


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

Da un puro punto di vista logico questo è quello che mi è venuta in mente.

Secondo il principio del buco del piccione, se esattamente 3 sono veri, allora aeb è vero, oppure c e d è vero. Quindi è solo una questione di anding ciascuno di quei casi con esattamente uno degli altri 2.

Tavolo della verità di Wolfram


Ciò equivale alla seconda soluzione di NameSpace.
Brilliand

@Brilliand Mi sembra diverso. I suoi xors tutti insieme per ottenere tutti i 3 o 1, quindi esclude quelli con 1 richiedendo almeno uno da 2 gruppi distinti. (riassunto come 1 o 3 e almeno 2). Il mio richiede entrambi da uno dei gruppi distinti e quindi esattamente uno dall'altro gruppo.
Cruncher

Se intendessi equivalente nel senso che mine <=> hisallora non so cosa dire in quanto ci si aspetterebbe.
Cruncher

Suppongo di voler dire che questa risposta è buona esattamente come la seconda soluzione di NameSpace è buona, senza aggiungere nulla di nuovo che la risposta (precedente) di NameSpace non coprisse. Bene, voterò comunque.
Brilliand

8

Se usi uno strumento di visualizzazione logica come Karnaugh Maps, vedi che questo è un problema in cui non puoi evitare un termine logico completo se vuoi scriverlo in una riga if (...). Lopina lo ha già mostrato, non è possibile scriverlo più semplice. Puoi tenerne conto un po ', ma resterà difficile da leggere per te E per la macchina.

Le soluzioni di conteggio non sono male e mostrano ciò che stai veramente cercando. Come si esegue il conteggio in modo efficiente dipende dal linguaggio di programmazione. Le soluzioni array con Python o LinQ sono belle da vedere, ma attenzione, questo è LENTO. Wolf's (a + b + x + y) == 3 funzionerà bene e velocemente, ma solo se la tua lingua equivale a "vero" con 1. Se "vero" è rappresentato da -1, dovrai testare -3: )

Se la tua lingua usa veri booleani, potresti provare a programmarla esplicitamente (io uso! = Come test 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" funziona solo se x, y sono di tipo booleano. Se sono di qualche altro tipo in cui 0 è falso e tutto il resto è vero, ciò può fallire. Quindi usa un XOR booleano o ((bool) x! = (Bool) y) oppure scrivi "if (x) return (y == false) else return (y == true);", che è un po 'più lavorare per il computer.

Se il tuo linguaggio di programmazione fornisce l'operatore ternary?:, Puoi accorciarlo

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

che mantiene un po 'di leggibilità o lo taglia in modo aggressivo

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

Questo codice esegue esattamente tre test logici (stato di a, stato di b, confronto di xey) e dovrebbe essere più veloce della maggior parte delle altre risposte qui. Ma devi commentarlo o non lo capirai dopo 3 mesi :)


8

Ci sono molte buone risposte qui; ecco una formulazione alternativa che nessun altro ha ancora pubblicato:

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

Grazie per la tua risposta, ma puoi aggiungere qualche commento su come funziona? Grazie.
Deanna,

(Mi dispiace prenderti cura di te, mi è stato dato come controllo di revisione. Almeno sono passato .. :))
Deanna

7

Simile alla prima risposta, ma Java puro:

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

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

Preferisco contarli come numeri interi perché rendono il codice più leggibile.


7

In Python , per vedere quanti di un iterabile di elementi sono True, usa sum(è abbastanza semplice):

Impostare

import itertools

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

Test effettivo

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

Produzione

(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

Se stai cercando la soluzione on-the-paper (non programmabile), allora gli algoritmi K-maps e Quine-McCluskey sono ciò che stai cercando, ti aiutano a minimizzare la tua funzione booleana.

Nel tuo caso, il risultato è

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

Se vuoi fare questa quantità programmata di variabili non fisse e una "soglia" personalizzata, allora semplicemente scorrere una lista di valori booleani e contare le occorrenze di "vero" è piuttosto semplice e diretto.


1
Cosa significa sovraccarico della barra? Vedo che si sta spostando verso il basso nell'elenco.
NameSpace

3
@NameSpace È una delle troppe notazioni IMO che le persone usano per esprimere "non".

5

Voglio restituire vero se e solo se 3 valori booleani su 4 sono veri.

Dati i 4 valori booleani, a, b, x, y, questa attività si traduce nella seguente istruzione C:

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

1
Bella trappola. Ciò presuppone che sia trueuguale a 1. Questo non è vero (nessun gioco di parole previsto) in tutte le lingue / casi. blogs.msdn.com/b/oldnewthing/archive/2004/12/22/329884.aspx
JensG

@JensG Hai ragione: rendo esplicito questo presupposto. Grazie :)
Wolf

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

è quello che vuoi. Fondamentalmente ho preso il tuo codice e aggiunto il controllo se in realtà 3 sono veri e non 3 sono falsi.


4

Una domanda di programmazione senza una risposta che implichi la ricorsione? Inconcepibile!

Ci sono abbastanza risposte "esattamente 3 su 4 verità", ma ecco una versione generalizzata (Java) per "esattamente m di n verità" (altrimenti la ricorsione non ne vale davvero la pena) solo perché puoi:

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);
}

Questo potrebbe essere chiamato con qualcosa del tipo:

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

che dovrebbe restituire true(perché 5 di 8 valori erano veri, come previsto). Non abbastanza soddisfatto delle parole "verità" e "falsità", ma non riesco a pensare a un nome migliore in questo momento .... Nota che la ricorsione si interrompe quando sono stati trovati troppi true o troppi falsevalori.


@ FélixSaparelli: Non sono sicuro che la "verità" si applichi qui ... sembrerebbe che tu ne sia felice true. Forse qualcosa del genere containsNumberOfTrueValues(). Per inciso: denominazione di Smalltalk sarebbe molto più adatto a questo, però: doesArray: someBooleans startingAt: anIndex containNumberOfTrueValues: anExpectedNumber foundSofar: aNumberFoundSoFar. Probabilmente troppo a lungo per i gusti di alcuni sviluppatori Java, ma i Smalltalker non hanno mai paura di un nome appropriato ;-)
Amos M. Carpenter

Questo è stato per lo più divertente. E containsTruthsignifica "contiene un po 'di verità non divulgata", letteralmente, quindi credo che vada bene.
Félix Saparelli,

3

Poiché la leggibilità è una grande preoccupazione, è possibile utilizzare una chiamata di funzione descrittiva (avvolgendo una qualsiasi delle implementazioni suggerite). Se questo calcolo deve essere eseguito in più punti, una chiamata di funzione è il modo migliore per ottenere il riutilizzo e chiarisce esattamente cosa stai facendo.

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

3

In PHP, rendendolo più dinamico (nel caso in cui cambi il numero di condizioni, ecc.):

$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)))

Mentre potrei dimostrare che questa è una buona soluzione, la risposta di Sam Hocevar è facile sia da scrivere che da capire in seguito. Nel mio libro questo lo rende migliore.


1

Ecco un po 'di codice c # che ho appena scritto perché mi hai ispirato:

Prende qualsiasi quantità di argomenti e ti dirà se n di essi sono veri.

    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;                
    }

e lo chiami così:

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

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

Quindi ora puoi testare 7/9 o 15/100 come vuoi.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.