Reputation: 4020
for example, suppose I need to do different things according to combinations of boolean values: cond_0,cond_1 and cond_2 :
cond_0 cond_1 cond_2
false false false a();
false false true b();
.
.
.
true true true h();
it looks as if mapping bit numbers to functions:
000:a()
001:b()
.
.
.
111:h()
while the general rule looks like very simple, I don't know how to write it without if-else, and the current form looks like that:
var f=function(cond_0,cond_1,cond_2){
if(!cond_0 && !cond_1 && !cond_2){
a();
}else if( cond_0 && !cond_1 && !cond_2)){
b();
}else if(!cond_0 && cond_1 && !cond_2)){
c();
}else if( cond_0 && cond_1 && !cond_2)){
d();
}else if(!cond_0 && !cond_1 && cond_2)){
e();
}else if( cond_0 && !cond_1 && cond_2)){
f();
}else if(!cond_0 && cond_1 && cond_2)){
g();
}else if( cond_0 && cond_1 && cond_2)){
h();
}
}
which is very long and hard to read. And when a new boolean condition cond_3 is added, it is horrible to modify the code:
if(!cond_0 && !cond_1 && !cond_2 && !cond_3){
a();
}else if( cond_0 && !cond_1 && !cond_2 !cond_3)){
b();
}
.
.
.
Is there any way to eliminate the if else, so that cond_0 , cond_1 and cond_2 can just appear once only inside the function, and also easy to add new function when cond_3 is added? I want something like:
var f=function(cond_0,cond_1,cond_2){
var magic=(000:a,001:b,010:c...);
magic(cond_0,cond_1,cond_2)();
}
Upvotes: 8
Views: 445
Reputation: 82297
- I need to do different things according to combinations of boolean values
- and also easy to add new function when cond_3 is added
There is no need to name them, just iterate over the set of arguments in the function.
//range of preset functions styled as OP described
function a(){ console.log('a'); }
function b(){ console.log('b'); }
function c(){ console.log('c'); }
function d(){ console.log('d'); }
function e(){ console.log('e'); }
function f(){ console.log('f'); }
function g(){ console.log('g'); }
function h(){ console.log('h'); }
function i(){ console.log('i'); }
function j(){ console.log('j'); }
function k(){ console.log('k'); }
function l(){ console.log('l'); }
function m(){ console.log('m'); }
//This function will take the arguments, reduce their boolean value
//to a 1 or 0 using |0, concatenate the string of 1's and 0's,
//parse out the string from binary to decimal, and then
//access the array's index correlating to the given decimal.
var truthTable = function(){
var callers = [a,b,c,d,e,f,g,h,i,j,k,l,m];
var tar = [].reduce.call(arguments,(p,c) => p+(c|0),"");
callers[parseInt(tar,2)]();
};
truthTable (true,true,false);
truthTable (true,false,true);
truthTable (true,true);
truthTable (true,true,false,false);
As written, this will scale as far as it needs to provided that the decimal index of each function in callers correlates to its truth table value.
Upvotes: 0
Reputation: 1161
You had the right idea at the top. You can encode the functions in a map just like you put together conceptually by implicitly casting booleans to integers. Below is an implementation which can be easily extended to handle more states/functions.
//initialization
var bitmap = {};
bitmap[0] = a;
bitmap[1] = b;
bitmap[10] = c;
bitmap[11] = d;
bitmap [110] = e;
var inputBools = [true, true, false];
pickFunction(inputBools);
function pickFunction(bools){
var key = 0;
for (var i = 0; i < bools.length; i++){
key += bools[bools.length-1-i]*Math.pow(10,i);
}
console.log(bitmap[key].call());
}
function a(){
return "a";
}
function b(){
return "b";
}
function c(){
return "c";
}
function d(){
return "d";
}
function e (){
return "e";
}
Upvotes: 0
Reputation: 665130
Use a bit of bitwise operations and binary literals as object keys:
function f(cond_0, cond_1, cond_2) {
const magic = {
0b000: a,
0b001: b,
0b010: c,
0b011: d,
0b100: e
0b101: f,
0b110: g,
0b111: h,
};
return magic[cond_2 << 2 | cond_1 << 1 | cond_0 << 0]();
}
This object is essentially the same as the array literal in @Slai's answer, just with explicit indices.
It gets much crazier if you directly declare your functions as methods of the object instead of naming them individually:
const magic = {
0b000() { console.log("a"); … },
0b001() { console.log("b"); … },
0b010() { console.log("c"); … },
0b011() { console.log("d"); … },
0b100() { console.log("e"); … },
0b101() { console.log("f"); … },
0b110() { console.log("g"); … },
0b111() { console.log("h"); … },
};
Upvotes: 1
Reputation: 2755
See this implementation. Here all the three parameters (boolean expected) are multiplied by their place values to form the number and then padded with '0'
to the desired length. This value is searched for in the magic
object and the function if defined is called.
var a = function() {
console.log('a() called');
};
var b = function() {
console.log('b() called');
};
var c = function() {
console.log('c() called');
};
var f = function(cond_0, cond_1, cond_2) {
var cond = ((cond_0 * 100) + (cond_1 * 10) + (cond_2)).toString().padStart(3, '0');
var magic = {
'000': a,
'001': b,
'010': c
};
if (typeof magic[cond] === 'function') {
magic[cond]();
} else {
console.log('No function defined for this cond');
}
}
f(false, false, false);
f(false, false, true);
f(false, true, false);
f(true, false, false);
Upvotes: 4
Reputation: 22876
Because true
to number is 1, true * 2
is 2, etc.. probably something like this:
function f(c0, c1, c2) { [a, b, c, d, e, f, g, h][+c0 +c1 * 2 +c2 * 4](); } // magic
Upvotes: 2
Reputation: 42277
Look at switches on mdn: switch
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/switch
Upvotes: -1