Un intervieweur m'a récemment posé cette question: étant donné trois variables booléennes, a, b et c, retourne vrai si au moins deux des trois sont vraies.
Ma solution suit:
boolean atLeastTwo(boolean a, boolean b, boolean c) {
if ((a && b) || (b && c) || (a && c)) {
return true;
}
else{
return false;
}
}
Il a dit que cela pouvait encore être amélioré, mais comment?
java
boolean
boolean-logic
utilisateur282886
la source
la source
atLeastTwo(iWantYou, iNeedYou, imEverGonnaLoveYou)
Réponses:
Plutôt que d'écrire:
Écrire:
Quant à l'expression elle-même, quelque chose comme ceci:
ou ceci (selon ce que vous trouvez plus facile à saisir):
Il teste
a
etb
exactement une fois, etc
au plus une fois.Références
la source
return hasGoodAttendance ? (passedCoursework || passed Exam) : (passedCoursework && passedExam)
, cela me va bien.atLeastTwo(hasgoodAttendance, passedCoursework, passedExam)
. L'idée de "au moins 2 bools sont vrais" est suffisamment générique pour mériter sa propre fonction.Juste pour le plaisir d'utiliser XOR pour répondre à un problème relativement simple ...
la source
Pourquoi ne pas l'implémenter littéralement? :)
En C, vous pouvez simplement écrire
a+b+c >= 2
(ou!!a+!!b+!!c >= 2
pour être très sûr).En réponse à la comparaison de TofuBeer du bytecode java, voici un test de performance simple:
Cela affiche les éléments suivants sur ma machine (exécutant Ubuntu sur Intel Core 2 + sun java 1.6.0_15-b03 avec HotSpot Server VM (14.1-b02, mode mixte)):
Première et deuxième itérations:
Itérations ultérieures:
Je me demande ce que pourrait faire une machine virtuelle Java qui dégrade les performances au fil du temps pour (a + b + c> = 2).
Et voici ce qui se passe si j'exécute java avec un
-client
commutateur VM:Mystère...
Et si je l'exécute dans GNU Java Interpreter , cela devient presque 100 fois plus lent, mais la
a&&b || b&&c || a&&c
version gagne alors.Résultats de Tofubeer avec le dernier code fonctionnant sous OS X:
Résultats de Paul Wagland avec un Mac Java 1.6.0_26-b03-383-11A511
la source
a+b+c >= 2
: cela ne fonctionne pas avec les négatifs, non? Vous devrez peut-être faire la!!a
chose, je ne suis pas sûr.Ce type de questions peut être résolu avec une carte de Karnaugh :
à partir de laquelle vous déduisez que vous avez besoin d'un groupe pour la première ligne et de deux groupes pour la première colonne, obtenant la solution optimale de lubrifiants polygéniques:
la source
La lisibilité devrait être l'objectif. Une personne qui lit le code doit comprendre immédiatement votre intention. Voici donc ma solution.
la source
Seq(true, true, false).map(if (_) 1 else 0).sum >= 2
Explication:
Si
a==b
, alors les deux sont vrais ou les deux sont faux. Si les deux sont vrais, nous avons trouvé nos deux vrais booléens et pouvons retourner vrai (en revenanta
). Si les deux sont faux, il ne peut pas y avoir deux vrais booléens même sic
c'est vrai, donc nous retournons faux (en revenanta
). Voilà la(a==b) ? a
partie. Et alors: c
? Eh bien, sia==b
est faux, alors exactement l'un dea
oub
doit être vrai, nous avons donc trouvé le premier vrai booléen, et la seule chose qui reste est sic
est également vrai, alors nous revenonsc
comme réponse.la source
a
et d'b
accord, ils ont le vote majoritaire, alors allez avec quoi que ce soit, sinon, ils ne sont pas d'accord, toutc
comme le vote décisif"Vous n'avez pas besoin d'utiliser les formes de court-circuit des opérateurs.
return (a & b) | (b & c) | (c & a);
Cela effectue le même nombre d'opérations logiques que votre version, mais est complètement sans branche.
la source
Voici une approche générale pilotée par les tests. Pas aussi "efficace" que la plupart des solutions proposées jusqu'à présent, mais claire, testée, fonctionnelle et généralisée.
la source
Résumer. Cela s'appelle l'algèbre booléenne pour une raison:
Si vous regardez les tables de vérité là-bas, vous pouvez voir que la multiplication est booléenne et, et simplement l'addition est xor.
Pour répondre à ta question:
la source
return ((a?1:0) + (b?1:0) + (c?1:0)) >= 2
.la source
Cela dépend vraiment de ce que vous entendez par «amélioré»:
Plus clair?
Terser?
Plus général?
Plus évolutif?
Plus rapide?
Laquelle est "améliorée" dépend fortement de la situation.
la source
Voici une autre implémentation utilisant map / Reduce. Cela évolue bien à des milliards de booléens © dans un environnement distribué. Utilisation de MongoDB:
Création d'une base
values
de données de booléens:Création de la carte, réduction des fonctions:
Edit : J'aime la réponse de CurtainDog à propos de l'application de map / réduire aux listes génériques, alors voici une fonction de carte qui prend un rappel qui détermine si une valeur doit être comptée ou non.
Exécution de la carte / réduction:
la source
Prendre les réponses (jusqu'à présent) ici:
et les exécuter via le décompilateur (javap -c X> results.txt):
Vous pouvez voir que les?: Ceux sont légèrement meilleurs que la version corrigée de votre original. Celui qui est le meilleur est celui qui évite complètement les branchements. C'est bon du point de vue de moins d'instructions (dans la plupart des cas) et mieux pour les parties de prédiction de branche du CPU, car une mauvaise estimation dans la prédiction de branche peut entraîner le blocage du CPU.
Je dirais que le plus efficace est celui de moonshadow dans l'ensemble. Il utilise le moins d'instructions en moyenne et réduit les risques de blocage du pipeline dans le CPU.
Pour être sûr à 100%, vous devrez connaître le coût (en cycles de processeur) de chaque instruction, qui, malheureusement, n'est pas facilement disponible (vous devrez consulter la source du point d'accès puis les spécifications des fournisseurs de CPU pour le moment). prises pour chaque instruction générée).
Voir la réponse mise à jour par Rotsor pour une analyse d'exécution du code.
la source
Un autre exemple de code direct:
Ce n'est évidemment pas le code le plus succinct.
Addenda
Une autre version (légèrement optimisée) de ceci:
Cela peut s'exécuter légèrement plus rapidement, en supposant que la comparaison avec 0 utilisera du code plus rapide (ou peut-être moins) que la comparaison avec 2.
la source
++n
est plus rapide quen++
parce que vous devez créer une autre copie avant de procéder à l'incrémentation .n
ci-dessus), tout compilateur décent compilera chaque++
opération dans une seule instruction CPU, qu'elle soit pré ou post.Encore une autre façon de le faire, mais pas très bonne:
Les
Boolean
valeurs du code de hachage sont fixées à 1231 pour true et 1237 pour false, donc auraient également pu utiliser<= 3699
la source
Les améliorations les plus évidentes sont les suivantes:
et alors
Mais ces améliorations sont mineures.
la source
Je n'aime pas le ternaire (d'
return a ? (b || c) : (b && c);
après la première réponse), et je ne pense pas avoir vu quelqu'un le mentionner. Il est écrit comme ceci:la source
À Clojure :
Usage:
la source
Je ne pense pas avoir encore vu cette solution:
Son avantage est qu'une fois qu'il atteint le nombre que vous recherchez, il casse. Donc, si c'était "au moins 2 de ces 1 000 000 valeurs sont vraies" alors que les deux premières sont réellement vraies, alors cela devrait aller plus vite que certaines des solutions les plus "normales".
la source
boolean ... boolValues
, il est plus facile d'appeler, mais prend toujours un tableauNous pouvons convertir les bools en entiers et effectuer cette vérification facile:
la source
Comme il n'a pas été précisé comment le code doit être amélioré, je m'efforcerai d'améliorer le code en le rendant plus amusant. Voici ma solution:
Si quelqu'un se demande si ce code fonctionne, voici une simplification utilisant la même logique:
}
Cela peut se résumer comme suit:
Mais maintenant ce n'est plus drôle.
la source
Trop de façons de le faire ...
la source
Solution AC.
ou vous pouvez préférer:
la source
la source
La manière la plus simple (IMO) qui n'est pas déroutante et facile à lire:
la source
(C && (A || B)) || (A && B)
vient de changer les noms de * variable ...Une interprétation littérale fonctionnera dans toutes les langues principales:
Mais je rendrais probablement la lecture plus facile, et extensible à plus de trois - quelque chose qui semble être oublié par de nombreux programmeurs:
la source
En complément de l'excellent message de @TofuBeer TofuBeer, considérez la réponse de @pdox pdox:
Considérez également sa version démontée comme donnée par "javap -c":
La réponse de pdox se compile en moins de code d'octet que n'importe laquelle des réponses précédentes. Comment son temps d'exécution se compare-t-il aux autres?
Au moins sur mon ordinateur, la réponse de pdox est juste un peu plus rapide que la réponse de @moonshadow moonshadow, faisant de pdox la plus rapide dans l'ensemble (sur mon ordinateur portable HP / Intel).
la source
En rubis:
[a, b, c].count { |x| x } >= 2
Qui pourrait être exécuté dans JRuby sur JavaVM. ;-)
la source
Il ne cherche probablement rien de compliqué comme les opérateurs de comparaison au niveau du bit (pas normalement compliqué mais avec des booléens, il est extrêmement étrange d'utiliser des opérateurs au niveau du bit) ou quelque chose de très détourné comme la conversion en int et leur résumé.
La façon la plus directe et la plus naturelle de résoudre ce problème est d'utiliser une expression comme celle-ci:
Mettez-le dans une fonction si vous préférez, mais ce n'est pas très compliqué. La solution est logiquement concise et efficace.
la source
En C:
la source