1

I have a script which checks the value of a series of flags before deciding on an execution pathway. Because of the way the script executes, the flag values are held as script properties, therefore string (not boolean).

Currently my if statement looks something like

if (flag1 == "false" && flag2 == "false" && flag3 == "false" && flag4 == "false") {
  do_work;
}

I wanted to make this easier to manage, so I tried

if (flag1 == flag2 == flag3 == flag4 == "false") {
  do_work;
}

but execution hung when I tried it, then stopped without producing any error message. Execution worked again when I reverted to the previous style.

Is there an efficient way to string multiple comparison checks together (like example 2), or do they all have to be individual checks (like example 1)?

2
  • 4
    The second expression is certainly not equivalent, stackoverflow.com/q/6967573/3001761 explains how it's evaluated. Maybe you want something like [flag1, ..., flagN].every((flag) => flag == "false")? Commented Nov 7 at 15:27
  • Understood. I'll check out your suggestion. Commented Nov 7 at 17:06

3 Answers 3

3

if (flag1 == flag2 == flag3 == flag4 == "false") resolves to

if (
   flag1 == flag2 /*"false" == "false" => true*/ 
   == flag3 /*true != "false" => false*/ 
   == flag4 /*false != "false" => false*/ 
   == "false" /*false != "false" => false*/) /* => false */ {...}

Here are a few alternatives. But as always: to make things easier, you have to do extra work first. In other words: being lazy is a lot of work.

Bitwise OR

Fwiw, str2Bool is part of my JQx library.

const [flag1, flag2, flag3, flag4] = ["false", "false", "false", "false"];
// step 1 to simplify if for flags 1-4: convert flag1=flag4
//  to an array of boolean (falsy) values
const flags1_4 = [flag1, flag2, flag3, flag4].map(str2Bool);

const [flag5, flag6, flag7, flag8] = ["true", "false", "true", "false"];
// same: array of boolean (truthy/falsy) values
const flags5_8 = [flag5, flag6, flag7, flag8].map(str2Bool);

// your second statement could be (but that's not much simpler)
if (flag1 === "false" && (flag1 === flag2) === (flag3 === flag4)) {
  console.log(
    `flag1 === "false" && (flag1 === flag2) === (flag3 === flag4)\n`,
    `=> yep: all false`)
}

// using an array of converted flags (step 1)
// gives the possibility to:
if (!flags1_4.some(flag => flag)) {
  console.log(`[${flags1_4}] => all false!`);
}

// same for flag5-flag8
if (flags5_8.some(flag => flag)) {
  console.log(`[${flags5_8}] => not all false!`);
}

// using numeric true/false values (0 or 1)
// and a bitwise OR operator
const [f1, f2, f3, f4] = flags1_4.map(v => +v);
switch((f1 | f2 | f3 | f4)) {
  case 0: console.log(`f1 | f2 | f3 | f4 => all false!`); break;
  case 1: console.log(`f1 | f2 | f3 | f4 => not all false!`); break;
  default: console.log(`undetermined`);
}

// a function to convert either 0 or 1, or
// some predefined strings to boolean
function str2Bool(value) {
  // Valid input values: 0|false|f|1|true|t (case insensitive)
  value = String(value).trim();
  switch (true) {
    case /^(0|false|f)$/i.test(value): return false;
    case /^(1|true|t)$/i.test(value):  return true;
    default: return false;
  }
}

If it's a number of strings that you need to compare (not necessary "true" or "false"), this may be an alternative:

const [s1, s2, s3] = "str1,str2,str3".split(`,`);
const [s4, s5, s6] = "str4,str4,str4".split(`,`);
const [flag1, flag2, flag3] = "false,false,false".split(`,`);

if (allEqual(flag1, flag2, flag3) === flag1) {
  console.log(`flag1, flag2, flag3 are indeed all "${flag1}"`);
}

const s1_3Equal = allEqual(s1, s2, s3) === "str1";
console.log( `${[s1, s2, s3]} are ${
  s1_3Equal ? `all equal` : `NOT all equal`}`)

console.log( `${[s4, s5, s6]} are ${
  allEqual(s4, s5, s6) === "str4"
    ? `all equal` : `NOT all equal`}`)

function allEqual(...strings) { 
  if (strings.length < 2) { return false;  }
  
  let prev = strings.shift();
  while (strings.length > 0) {
    const str = strings.shift();
    if (str !== prev) { return false; }
    prev = str;
  }
  
  return prev;
}

Sign up to request clarification or add additional context in comments.

Comments

1

If your using multiple flags and want to check that they all have same Boolean (or string) value, then use every() function in javascript.

if ([flag1, flag2, flag3, flag4].every(f => f === "false")) {
  do_work();
}

what it does, checks all elements in array satisfy the condition f === "false" , also easy to scale.

Comments

0

There is an old-school strategy you could try. Its centered around bitfields and bitmasks. Its quite flexible and not as computationally heavy as other approaches.

Instead of passing around individual Boolean properties, store state in one numeric variable that represents the on/off states of all of your flags - where each flag is represented by a bit that is a power of 2.

Let's use Javascript's binary number syntax to illustrate what this could look like for 8 flags.

let flags = 0b00000000;

Each flag is represented by one of the 8 digits after the prefix '0b'. And they can be in one of two states ON - represented by 1, or OFF represented by 0 - which you can mentally map to TRUE and FALSE.

Let's assume the flags are assigned from right to left. Flag_1 is represented by the first digit on the far right, Flag_2 is to the left of Flag_1, and so on until we get to the 8th digit from the right that represents Flag_8.

If you set the flags variable as follows:

flags = 0b10010111;

You have effectively 'turned on' flags 8, 5, 3, 2, and 1.

To check if flags 3, 2, and 1 are all collectively enabled, you can use a simple combo of bitwise and equality operators to check:

if ((flags & 0b00000111) === 0b00000111) { /* do stuff */ }

You may also want to check if a set of flags are 'turned off'.

To check if flags 3, 2, and 1 are all collectively disabled, the following would suffice:

if ((flags & 0b00000111) === 0) { /* do stuff */ }

To make the code more readable you can define constants for common conditions you test for, and wrap the enable and disable tests in their own respective functions:

const FLAGS_3_2_1 = 0b00000111;

const flagsEnabled = (condition, flags) => (flags & condition) === condition;
const flagsDisabled = (condition, flags) => (flags & condition) === 0;

if (flagsEnabled(FLAGS_3_2_1, flags)) {/* do stuff */}

if (flagsDisabled(FLAGS_3_2_1, flags)) {/* do stuff */}

If you don't like typing out a bunch of ones and zeros, you have the option of using hexadecimal numbers to define conditions instead.

const FLAGS_3_2_1 = 0x07;

If you're into functional programming you can take this even further:

// Conditions to test for
const FLAGS_3_2_1 = 0x07;
const FLAGS_8_7_4_1 = 0xC9;

const generateFlagsEnabledChecker = condition => flags => (flags & condition) === condition;
const generateFlagsDisabledChecker = condition => flags => (flags & condition) === 0;

const flags321Enabled = generateFlagsEnabledChecker(FLAGS_3_2_1);
const flags321Disabled = generateFlagsDisabledChecker(FLAGS_3_2_1);

const flags8741Enabled = generateFlagsEnabledChecker(FLAGS_8_7_4_1);
const flags8741Disabled = generateFlagsDisabledChecker(FLAGS_8_7_4_1);

let flagsToCheck = 0b11001001;

// returns false; bits 3 & 2 are disabled
console.log('Flags 3, 2, and 1 collectively enabled = %s', flags321Enabled(flagsToCheck));
// returns false; bit 1 is enabled
console.log('Flags 3, 2, and 1 collectively disabled = %s', flags321Disabled(flagsToCheck));


// returns true
console.log('Flags 8, 7, 4, and 1 collectively enabled = %s', flags8741Enabled(flagsToCheck));
// returns false
console.log('Flags 8, 7, 4, and 1 collectively disabled = %s', flags8741Disabled(flagsToCheck));

You can store either the binary or hexadecimal representation as a string in properties service and convert it to a number as needed using parseInt(). Just remember to use the appropriate radix as follows:

let convertedFromHex = parseInt(stringHexValue, 16);
let convertedFromBinary = parseInt(stringBinValue, 2);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.