Um entrevistador recentemente me fez esta pergunta: dadas três variáveis booleanas, a, bec, retornam true se pelo menos duas das três forem verdadeiras.
Minha solução é a seguinte:
boolean atLeastTwo(boolean a, boolean b, boolean c) {
if ((a && b) || (b && c) || (a && c)) {
return true;
}
else{
return false;
}
}
Ele disse que isso pode ser melhorado ainda mais, mas como?
java
boolean
boolean-logic
user282886
fonte
fonte
atLeastTwo(iWantYou, iNeedYou, imEverGonnaLoveYou)
Respostas:
Em vez de escrever:
Escreva:
Quanto à própria expressão, algo como isto:
ou isso (o que você achar mais fácil de entender):
Ele testa
a
eb
exatamente uma vez, ec
no máximo uma vez.Referências
fonte
return hasGoodAttendance ? (passedCoursework || passed Exam) : (passedCoursework && passedExam)
, isso parece bom para mim.atLeastTwo(hasgoodAttendance, passedCoursework, passedExam)
. A idéia de "pelo menos 2 bools são verdadeiros" é genérica o suficiente para merecer sua própria função.Apenas para usar o XOR para responder a um problema relativamente direto ...
fonte
Por que não implementá-lo literalmente? :)
Em C, você pode escrever
a+b+c >= 2
(ou!!a+!!b+!!c >= 2
para ser muito seguro).Em resposta à comparação do TofuBeer do bytecode Java, aqui está um teste de desempenho simples:
Isso imprime o seguinte na minha máquina (executando o Ubuntu no Intel Core 2 + sun java 1.6.0_15-b03 com a VM do HotSpot Server (14.1-b02, modo misto)):
Primeira e segunda iterações:
Iterações posteriores:
Gostaria de saber o que java VM fazer isso degrada desempenho ao longo do tempo no caso (a + b + c> = 2).
E aqui está o que acontece se eu executar o java com um
-client
switch VM:Mistério...
E se eu executá-lo no GNU Java Interpreter , fica quase 100 vezes mais lento, mas o
a&&b || b&&c || a&&c
versão vence então.Resultados do Tofubeer com o código mais recente executando o OS X:
Resultados de Paul Wagland com um Mac Java 1.6.0_26-b03-383-11A511
fonte
a+b+c >= 2
: isso não funciona com negativos, certo? Você pode ter que fazer a!!a
coisa, não tenho certeza.Esse tipo de pergunta pode ser resolvido com um mapa de Karnaugh :
a partir do qual você deduz que precisa de um grupo para a primeira linha e dois grupos para a primeira coluna, obtendo a solução ideal de poligenelubrificantes:
fonte
Legibilidade deve ser o objetivo. Alguém que lê o código deve entender sua intenção imediatamente. Então aqui está a minha solução.
fonte
Seq(true, true, false).map(if (_) 1 else 0).sum >= 2
Explicação:
Se
a==b
, então ambos são verdadeiros ou ambos são falsos. Se ambos são verdadeiros, encontramos nossos dois booleanos verdadeiros e podemos retornar true (retornandoa
). Se ambos são falsos, não pode haver dois booleanos verdadeiros, mesmo quec
sejam verdadeiros; portanto, retornamos falso (retornandoa
). Essa é a(a==b) ? a
parte. Que tal: c
? Bem sea==b
for falso, então exatamente um dea
oub
deve ser verdadeiro; portanto, encontramos o primeiro booleano verdadeiro, e a única coisa que importa é sec
também é verdadeiro; portanto, retornamosc
como resposta.fonte
a
eb
concordam, eles têm a maioria, para ir com o que é, então, eles discordam, entãoc
é o voto de qualidade"Você não precisa usar as formas de curto-circuito dos operadores.
return (a & b) | (b & c) | (c & a);
Isso executa o mesmo número de operações lógicas que sua versão, porém é completamente sem ramificação.
fonte
Aqui está uma abordagem geral orientada a testes. Não é tão "eficiente" quanto a maioria das soluções oferecidas até agora, mas é clara, testada, funcionando e generalizada.
fonte
Resumir. É chamado álgebra booleana por um motivo:
Se você olhar para as tabelas verdadeiras, poderá ver que a multiplicação é booleana e, simplesmente, adição é xor.
Para responder sua pergunta:
fonte
return ((a?1:0) + (b?1:0) + (c?1:0)) >= 2
.fonte
Realmente depende do que você quer dizer com "aprimorado":
Mais claro?
Terser?
Mais general?
Mais escalável?
Mais rápido?
Qual deles é "melhorado" depende muito da situação.
fonte
Aqui está outra implementação usando mapear / reduzir. Isso escala bem para bilhões de booleanos © em um ambiente distribuído. Usando o MongoDB:
Criando um banco
values
de dados de booleanos:Criando o mapa, reduza as funções:
Edit : Eu gosto da resposta do CurtainDog sobre aplicar o mapa / reduzir a listas genéricas, então aqui vai uma função de mapa que recebe um retorno de chamada que determina se um valor deve ser contado ou não.
Mapa em execução / redução:
fonte
Tomando as respostas (até agora) aqui:
e executando-os pelo descompilador (javap -c X> results.txt):
Você pode ver que os?: Ones são um pouco melhores que a versão corrigida do seu original. O melhor é o que evita ramificações por completo. Isso é bom do ponto de vista de menos instruções (na maioria dos casos) e melhor para partes de previsão de ramificação da CPU, pois uma suposição incorreta na previsão de ramificação pode causar paralisação da CPU.
Eu diria que o mais eficiente é o da sombra da lua em geral. Ele usa o menor número de instruções, em média, e reduz a chance de paralisações de pipeline na CPU.
Para ter 100% de certeza de que você precisaria descobrir o custo (em ciclos de CPU) para cada instrução, que infelizmente não está disponível (você precisaria procurar a fonte do hotspot e, em seguida, os fornecedores de CPU especifica o tempo. tomadas para cada instrução gerada).
Consulte a resposta atualizada por Rotsor para uma análise em tempo de execução do código.
fonte
Outro exemplo de código direto:
Não é o código mais sucinto, obviamente.
Termo aditivo
Outra versão (ligeiramente otimizada) disso:
Isso pode ser um pouco mais rápido, supondo que a comparação contra 0 use código mais rápido (ou talvez menos) do que a comparação contra 2.
fonte
++n
é mais rápido do quen++
porque você precisa criar outra cópia antes de fazer o incremento .n
acima), qualquer compilador decente compilará cada++
operação em uma única instrução de CPU, seja pré ou pós.Ainda outra maneira de fazer isso, mas não muito boa:
Os
Boolean
valores de código de hash são fixados em 1231 para true e 1237 para false, portanto, poderiam igualmente ter usado<= 3699
fonte
O conjunto mais óbvio de melhorias são:
e depois
Mas essas melhorias são pequenas.
fonte
Não gosto de ternário (
return a ? (b || c) : (b && c);
da primeira resposta) e acho que não vi ninguém mencionar isso. Está escrito assim:fonte
Em Clojure :
Uso:
fonte
Acho que ainda não vi essa solução:
Sua vantagem é que, uma vez atingido o número que você está procurando, ele quebra. Portanto, se isso foi "pelo menos 2 dos 1.000.000 valores são verdadeiros", onde os dois primeiros são realmente verdadeiros, deve ser mais rápido do que algumas das soluções mais "normais".
fonte
boolean ... boolValues
por isso é mais fácil de chamada, mas ainda recebe um arrayPodemos converter os bools em números inteiros e executar esta verificação fácil:
fonte
Como não foi especificado como o código deve ser aprimorado, tentarei melhorar o código, tornando-o mais divertido. Aqui está a minha solução:
Caso alguém esteja se perguntando se esse código funciona, aqui está uma simplificação usando a mesma lógica:
}
Isso pode ser resumido ainda mais ao seguinte:
Mas agora não é mais engraçado.
fonte
Muitas maneiras de fazer isso ...
fonte
Solução CA.
ou você pode preferir:
fonte
fonte
A maneira mais simples (IMO) que não é confusa e fácil de ler:
fonte
(C && (A || B)) || (A && B)
acabou de alterar os nomes das variáveis * ...Uma interpretação literal funcionará em todos os principais idiomas:
Mas eu provavelmente facilitaria a leitura e a expansão para mais de três pessoas - algo que parece ser esquecido por muitos programadores:
fonte
Como complemento da excelente publicação de @TofuBeer TofuBeer, considere a resposta de @pdox pdox:
Considere também sua versão desmontada, conforme fornecida por "javap -c":
A resposta do pdox é compilada com menos código de bytes que qualquer uma das respostas anteriores. Como o tempo de execução se compara aos outros?
Pelo menos no meu computador, a resposta do pdox é apenas um pouco mais rápida que a resposta de @moonshadow moonshadow, tornando o pdox o mais rápido em geral (no meu laptop HP / Intel).
fonte
Em Ruby:
[a, b, c].count { |x| x } >= 2
O que poderia ser executado no JRuby no JavaVM. ;-)
fonte
Ele provavelmente não está procurando nada complicado como operadores de comparação bit a bit (normalmente não complicado, mas com booleanos, é extremamente estranho usar operadores bit a bit) ou algo que seja muito indireto, como converter para int e resumi-los.
A maneira mais direta e natural de resolver isso é com uma expressão como esta:
Coloque-o em uma função, se preferir, mas não é muito complicado. A solução é logicamente concisa e eficiente.
fonte
Em C:
fonte