Lógica para testar se 3 de 4 são Verdadeiros


163

Quero retornar Truese e somente se 3 de 4 valores booleanos forem verdadeiros.

O mais próximo que cheguei é (x ^ y) ^ (a ^ b):

O que devo fazer?


10
Hmm, a única maneira de pensar sem a fórmula matemática é usar count. Boa pergunta! :)
Eu sou Cavic em 7/03/2014

10
Sua idéia não é ruim, mas você deve aceitar as negações: not a ^ not b ^ not c ^ not dé verdade quando exatamente um dos valores negados é verdadeiro. Isso significa que, pelos valores originais, exatamente um era falso.
Ingo

23
Qual é o seu problema real por trás desses detalhes?
Wolf

5
@Ingo not a ^ not b ^ not c ^ not d return true onde apenas um é false E onde 3 são false.
NameSpace

9
A solução óbvia para não contar é (!a&&b&&c&&d) || (a&&!b&&c&&d) || (a&&b&&!c&&d) || (a&&b&&c&&!d).
Jason C #

Respostas:


248

Sugiro escrever o código de uma maneira que indique o que você quer dizer. Se você deseja que 3 valores sejam verdadeiros, parece-me natural que o valor 3 apareça em algum lugar.

Por exemplo, em C++:

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

Isso está bem definido em C++: standard (§4.7/4)indica que a conversão boolpara intfornece os valores esperados 0 ou 1.

Em Java e C #, você pode usar a seguinte construção:

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

23
Esta é uma boa resposta. Parece um caso dessa coisa X / Y. "Ele quer fazer X usando Y, mas não sabe como Y. Em vez de perguntar a X, ele pergunta a Y." A menos que ele esteja projetando um circuito lógico ou algo assim (e então ele estaria no site errado), a melhor maneira de fazer isso é de uma maneira que seja legível .
NothingsImpossible

2
@NothingsImpossible Não há nada de XY na pergunta. É uma pergunta clara e direta sobre como resolver um problema razoavelmente comum na programação. O Y é irrelevante.
Ярослав Рахматуллин

Obrigado! Isso é realmente o que eu pretendia fazer, mas minha ideia era tão desajeitada que procurei lógica booleana.
Simon Kuang

3
if (!!a + !!b + !!c + !!d == 3)é mais fácil de escrever, embora eu não sei se compiladores otimizar isso ou não
phuclv

2
Observe que no c ++ a conversão de bool para int não é necessária.
PlasmaHH

90

# 1: Usando uma ramificação?: 3 ou 4 operações

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

# 2 Não ramificação, 7 operações

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

Na época em que utilizava o perfil de tudo, descobri que as soluções que não eram de ramificação eram operação e operação bastante mais rápidas, pois a CPU podia prever melhor o caminho do código e executar mais operações em conjunto. Há cerca de 50% menos trabalho na declaração de ramificação aqui.


18
+1 - enquanto as outras respostas são melhores para a maioria das linguagens de programação, o número 2 é a melhor resposta na lógica booleana pura.
Brilliand


68

Se fosse Python, eu teria escrito

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

Ou

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

Ou

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

Ou

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

Ou

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

Ou

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

Ou

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

Tudo isso funciona, já que os booleanos são subclasses de números inteiros em Python.

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

Ou, inspirado por esse truque legal ,

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

17
+1 Isso resolve o problema, traduzindo-o corretamente para Python.
Wolf

Isso é um pouco perigoso, porque as pessoas podem retornar qualquer número inteiro diferente de zero em um contexto booleano em python. O velho truque C funciona em python também: a=5;not not a == 1. A desvantagem de não ter um tipo booleano real.
Voo

@Voo We also have bool:) #
thefourtheye

@thefourtheye Ah sim verdade, muito melhor do que o truque de dupla negação / hack.
Voo

1
Ou ... ou .... ou .... Deve haver uma - e preferencialmente apenas uma - maneira óbvia de fazê-lo. : - / :-)
rz.

53

Forma normal longa, mas muito simples, (disjuntiva):

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

Pode ser simplificado, mas isso exige mais reflexão: P


2
@ Ben, que apenas fornece várias formas normais, nas quais isso já está (DNF).
Riking

8
Que tal (a & b & (c ^ d)) | ((a ^ b) & c & d)?
precisa saber é o seguinte

2
Sim, @immibis, de acordo com a Wolfram Alpha, seu DNF é a fórmula que escrevi, portanto é a mesma função booleana.
Gastón Bengolea

2
+1 porque acho que alguém que lê o código entenderá o que está sendo tentado mais rapidamente do que com outras respostas.
Boluc Papuccuoglu


22

Se você quiser usar essa lógica em uma linguagem de programação, minha sugestão é

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

Ou, se desejar, você pode colocar tudo isso em uma única linha:

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

Além disso, você pode generalizar esse problema para 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
Bata-me para isso. A legibilidade supera a inteligência, sempre. 1
MikeTheLiar

20

Essa resposta depende do sistema de representação, mas se 0 é o único valor interpretado como falso e not(false)sempre retorna o mesmo valor numérico, então not(a) + not(b) + not(c) + not(d) = not(0)deve fazer o truque.


18

Tendo em mente que, para questões de programação, em vez de meros problemas lógicos, a resposta obviamente depende da escolha de uma linguagem de programação. Alguns idiomas suportam recursos incomuns para outros.

Por exemplo, em C ++, você pode testar suas condições com:

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

Essa deve ser a maneira mais rápida de verificar os idiomas que suportam a conversão automática (de baixo nível) de tipos booleanos para números inteiros. Mas, novamente, não há resposta geral para esse problema.


2
Esta é a resposta que eu ia postar. Uma coisa a acrescentar, dependendo da linguagem de programação usada, a resposta que você deseja seria -3. No VB, True = -1.
Tom Collins


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

A primeira expressão procura 1 ou 3 trueem 4. A segunda elimina 0 ou 1 (e às vezes 2) trueem 4.


11

Java 8, filtre os valores falsos e conte os demais valores verdadeiros:

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

Então você pode usá-lo da seguinte maneira:

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

Generaliza facilmente a verificação nde mitens verdadeiros.


11

Para verificar se pelo menos ntodas Booleansão verdadeiras, (n deve ser menor ou igual ao número total de Boolean: p)

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

Edit : Após o comentário do @ Cruncher

Para verificar 3 booleande 4

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

Outro :

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


OP quer exatamente n, não pelo menos n. Mas isso é uma mudança fácil a partir desta solução
Cruncher

2
@Wolf essa pergunta pertence ao StackUnderflow.com: p
Não é um bug

10

Aqui está uma maneira de resolvê-lo em C # com o LINQ:

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

10

Essa é a função booleana simétrica S₃(4). Uma função booleana simétrica é uma função booleana que depende apenas da quantidade de entradas configuradas, mas não depende de quais entradas elas são. Knuth menciona funções desse tipo na seção 7.1.2 do volume 4 de The Art of Computer Programming.

S₃(4) pode ser calculado com 7 operações da seguinte maneira:

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

Knuth mostra que isso é ideal, o que significa que você não pode fazer isso em menos de sete operações usando os operadores normais: &&, || , ^, <,e >.

No entanto, se você quiser usar isso em um idioma usado 1para true e 0false, também poderá usar a adição facilmente:

x + y + a + b == 3

o que deixa sua intenção bem clara.


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

Do ponto de vista da lógica pura, é isso que eu criei.

Pelo princípio do buraco do pombo, se exatamente 3 são verdadeiros, então aeb são verdadeiros ou c e d são verdadeiros. Então é só uma questão de combinar cada um desses casos com exatamente um dos outros 2.

Tabela da verdade de Wolfram


Isso é equivalente à segunda solução do NameSpace.
Brilliand

@Brilliand Parece diferente para mim. Seus xors estão todos juntos para obter todos os 3 ou 1 e exclui os com 1, exigindo pelo menos um de 2 grupos distintos. (resumido em 1 ou 3 e pelo menos 2). O meu exige ambos de um dos grupos distintos e, em seguida, exatamente um do outro grupo.
Cruncher

Se você quis dizer equivalente no sentido de que mine <=> hisnão sei o que dizer, como seria de esperar.
Cruncher

Acho que quis dizer que essa resposta é boa exatamente da mesma maneira que a segunda solução do NameSpace é boa, sem acrescentar nada de novo que a resposta do NameSpace (anterior) não tenha coberto. Bem, eu vou votar de qualquer maneira.
Brilliand

8

Se você usar uma ferramenta de visualização lógica como o Karnaugh Maps, verá que este é um problema em que não poderá evitar um termo lógico completo se quiser escrevê-lo em uma linha se (...). Lopina já mostrou, não é possível escrever mais simples. Você pode calcular um pouco, mas será difícil ler para você E para a máquina.

As soluções de contagem não são ruins e mostram o que você realmente procura. Como você faz a contagem de maneira eficiente depende da sua linguagem de programação. As soluções de array com o Python ou LinQ são boas de se olhar, mas cuidado, é SLOW. Wolf (a + b + x + y) == 3 funcionará bem e rápido, mas somente se o seu idioma igualar "verdadeiro" a 1. Se "verdadeiro" for representado por -1, você terá que testar -3: )

Se seu idioma usa booleanos verdadeiros, você pode tentar programá-lo explicitamente (eu uso! = Como teste 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" funciona apenas se x, y são do tipo booleano. Se eles são algum outro tipo em que 0 é falso e tudo o mais é verdadeiro, isso pode falhar. Em seguida, use um XOR booleano ou ((bool) x! = (Bool) y) ou escreva "if (x) return (y == false) else return (y == true);", que é um pouco mais trabalhar para o computador.

Se sua linguagem de programação fornecer o operador ternário?:, Você poderá reduzi-lo para

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

que mantém um pouco de legibilidade ou reduz de forma agressiva para

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

Esse código faz exatamente três testes lógicos (estado de a, estado de b, comparação de xey) e deve ser mais rápido que a maioria das outras respostas aqui. Mas você precisa comentar ou não entenderá depois de 3 meses :)


8

Há muitas boas respostas aqui; aqui está uma formulação alternativa que ninguém mais postou ainda:

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

Obrigado por sua resposta, mas você pode adicionar algum comentário sobre como ele funciona? Obrigado.
Deanna

(Desculpe a pegar em você, eu estava dado como uma auditoria de revisão Pelo menos eu passei .. :).)
Deanna

7

Semelhante à primeira resposta, mas puro Java:

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

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

Eu prefiro contá-los como números inteiros, porque cria um código mais legível.


7

No Python , para ver quantos elementos iteráveis ​​são True, use sum(é bem direto):

Configuração

import itertools

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

Teste Real

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

Resultado

(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 você está buscando a solução no papel (sem programação), os algoritmos K-maps e Quine-McCluskey são o que você procura, eles ajudam a minimizar sua função booleana.

No seu caso, o resultado é

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

Se você deseja fazer isso programaticamente, uma quantidade não fixa de variáveis ​​e um "limite" personalizado, simplesmente iterando através de uma lista de valores booleanos e contando ocorrências de "true" é bastante simples e direto.


1
O que significa a sobrecarga da barra? Percebo que está descendo a lista.
NameSpace

3
@NameSpace É uma das muitas notações da IMO que as pessoas usam para expressar "not".

5

Eu quero retornar true se e somente se 3 de 4 valores booleanos forem verdadeiros.

Dados os 4 valores booleanos, a, b, x, y, esta tarefa se traduz na seguinte instrução C:

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

1
Boa armadilha. Isso assume trueigual a 1. Isso não é verdade (sem trocadilhos) em todos os idiomas / casos. blogs.msdn.com/b/oldnewthing/archive/2004/12/22/329884.aspx
JensG 17 /

@ JensG Você está certo: eu faço essa suposição explícita. Thx :)
Wolf

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

é o que você quer. Basicamente, peguei o seu código e adicionei a verificação se na verdade 3 são verdadeiros e não 3 são falsos.


4

Uma pergunta de programação sem resposta envolvendo recursão? Inconcebível!

Existem respostas suficientes "exatamente 3 em 4 verdadeiras", mas aqui está uma versão generalizada (Java) para "exatamente m fora de n verdadeiras" (caso contrário, a recursão não vale a pena) apenas porque você pode:

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

Isso pode ser chamado com algo como:

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

que deve retornar true(porque 5 de 8 valores eram verdadeiros, conforme o esperado). Não está muito satisfeito com as palavras "verdadeiras" e "falsas", mas não consegue pensar em um nome melhor no momento ... Observe que a recursão para quando valores demais true ou muitos falseforam encontrados.


@ FélixSaparelli: Não sei se a "verdade" se aplica aqui ... parece que você está feliz com apenas uma true. Talvez algo parecido containsNumberOfTrueValues(). Como um aparte: nomeação do Smalltalk seria muito mais adequado para isso, porém: doesArray: someBooleans startingAt: anIndex containNumberOfTrueValues: anExpectedNumber foundSofar: aNumberFoundSoFar. Provavelmente muito tempo para gostos algumas devs Java, mas Smalltalkers não têm medo de nomenclatura adequada ;-)
Amos M. Carpenter

Isso foi principalmente engraçado. E containsTruthsignifica "contém uma quantidade não revelada de verdade", literalmente, então eu acredito que está tudo bem.
Félix Saparelli

3

Como a legibilidade é uma grande preocupação, você pode usar uma chamada de função descritiva (envolvendo qualquer uma das implementações sugeridas). Se esse cálculo precisar ser feito em vários locais, uma chamada de função é a melhor maneira de obter a reutilização e deixa claro exatamente o que você está fazendo.

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

3

No PHP, tornando-o mais dinâmico (caso você altere o número de condições, etc.):

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

Embora eu possa mostrar que essa é uma boa solução, a resposta de Sam Hocevar é fácil de escrever e entender mais tarde. No meu livro, isso melhora.


1

Aqui está um código c # que acabei de escrever porque você me inspirou:

É preciso qualquer quantidade de argumentos e informa se n deles são verdadeiros.

    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 você chama assim:

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

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

Agora você pode testar 7/9 ou 15/100 como desejar.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.