Two or Three max.
There are three input thus there need be only 3 tests max, any more and the are working on information already known.
The best is when you find two inputs that are true
, that means you can return false
without testing the last value.
The current given answers all need more than three tests in the worst cases and at best three tests.
The flowing will do three test worst case and 2 best
function onlyOne(a, b, c) {
if (a) {
if (b) { return false }
return c ? false : true;
}
if (b) { return c ? false : true }
return c ? true : false;
}
Or as
function onlyOne(a, b, c) {
if (a) { return b ? false : c ? false : true }
return b ? (c ? false : true) : (c ? true : false);
}
There is also a time invariant solution that always has the same performance, though its best and worst is 3 tests. Both use lookup tables
const T = true, F = false, look = [F,T,T,F,T,F,F,F];
const onlyOne = (a, b, c) => look[(a ? 1 : 0) + (b ? 2 : 0) + (c ? 4 : 0)];
Or
const T = true, F = false, look = [F,F,T,F];
const onlyOne = (a, b, c) => look[!a + !b + !c];
Update
I would like to clarify some common misunderstanding about Javascript. Dogma and the fanaticism that enforces it has no place in the coding community. Hence the update.
(Ternaries have multiple paths) Wrong.
There are two types of code in Javascript Expressions and Statement
- Expression evaluate to a value. eg
"a"
, 0
, a = b
, (a,b)
, foo()
- Statements do not have a value. eg
if
, else if
, while
, do ... while
, for
, switch
, return
Ternaries are expressions, they are not statements. Ternaries are expression selectors and can be thought of as lookup index rather than a conditional branch.
The following is another way of writing a ternary like expression in javascript.
var c = true;
var res = ([100, 200])[+c]; // res is assign 200
c = false;
res = ([100, 200])[+c]; // res is assign 100
Because ternaries do not split code flow you can not use ternaries to introduce statement that cause code flow to branch.
// Code flow is not split thus the next to can not work
a ? a++ : return; // Error unexpected token
a ? continue : break; // Error unexpected token
// need to diverge code flow to do the following
if (a) a++; else return;
if (a) continue; else break;
(Branching means low javascript performance) Wrong.
Modern CPUs use look ahead instruction pipelines that fetch instruction from memory while at the same time performing operations. They do this to improve performance. However conditional branching can mean the wrong path is fetched. When this happens the pipeline needs to rollback and fetch the correct path, meanwhile the CPU must wait until at least the first instruction has loaded. This results in downgraded performance.
This problem can be reduced using various method such as branch prediction. The CPU uses past results to guess which way to go next time.
Many JS codes believe that diverging code flow is poor because it may trigger the CPU instruction pipeline to rollback. That it is better to use syntax that avoids diverging code flow so to avoid this penalty.
This is not true, the only way to avoid CPU instruction branching in JavaScript is by not using operators in expressions (which is pointless) or by using statements that don't require a type check eg return foo
;
Javascript is loosely typed, which means that every expression that contains a operator must have its type checked for the operator to be applied correctly. There is no way to avoid it. Even optimized code needs to have a test to make sure a type has not changed
You can not avoid CPU instruction pipeline rollback when writing Javascript expressions
Semantic and syntactic meaning
All code represents meaningful concepts, an abstraction of the zeros and ones that lay underneath, these abstractions are split into two types.
A language is comprised of building blocks and a set of rules that define how these blocks relate to each other. These blocks and rules are the syntax of a language. They are non contextual and have a fixed fixed meaning.
- Semantic meaning (abstraction)
Using the blocks (tokens) and rules of syntax we can create expressions and statements. This grouping along with the context have a semantic meaning. Semantic meaning is not fixed, and the same code have entirely different semantic meaning depending on the context.
Semantic meaning is a fundamental part of writing code, its how we abstract code into high and more meaningful representation of all those bits.
return input1 || input2 || input3
? \$\endgroup\$true
if more than one of the arguments are true. onlyOne should return true only if exactly one of the three arguments are truthy. Otherwise, it should return false. \$\endgroup\$