Generate All Boolean Array Combinations

While writing Go tests for goxplorer, I wanted to test all boolean flags combinations without having to cascade for loops.
This first method came to mind:

package main

import (
	"fmt"
)

func stob(bf []bool, s string) {
	for i, b := range s {
		if b == '0' {
			bf[i] = false
		} else {
			bf[i] = true
		}
	}
}

func main() {
	bf := []bool{false, false, false, false, false}

	for i := 0; i < 32; i++ {
		b := fmt.Sprintf("%b", i)
		stob(bf, b)
		fmt.Println(bf)
	}
}

Because the fastest way of generating every possible combination of 5 bits is to count from 0 to 31, i.e. 2^5, i.e. 32. The second trick here is to use fmt.Sprintf("%b") to generate a string representing the binary value.
It works, but I found the idea of using strings too heavy for a “binary” task.
A friend came to me with a barbaric bits field solution I found way too smart / complicated :), so I thought about another option but also using bits field, and thought about the following: how to tell if a field is a 1? One of the many options is the or binary operator; indeed, if a field is 0 and is “or’ed” with a 1, its value will become 1, if the initial value is 1, it will not change. Remember or truth table?

a b result
0 0 0
0 1 1
1 0 1
1 1 1

Here’s the equivalent code:

package main

import (
	"fmt"
)

func btoflag(bf []bool, n int) {
	for i, _ := range bf {
		if n|(1<<i) > n {
			bf[i] = false
		} else {
			bf[i] = true
		}
	}
}

func main() {
	bf := []bool{false, false, false, false, false}
	for i := 0; i < 32; i++ {
		btoflag(bf, i)
		fmt.Println(bf)
	}
}

Yet again, I tend to avoid else as much as possible to respect Go‘s “happy ending” best practices, and as is often happens, this btoflag()'s is useless, simply declare / initialize bf at each occurrence of the loop:

func btoflag(bf []bool, n int) {
	for i, _ := range bf {
		if n|(1<<i) > n {
			bf[i] = false
		}
	}
}

func main() {
	for i := 0; i < 32; i++ {
		bf := []bool{true, true, true, true, true}
		btoflag(bf, i)
		fmt.Println(bf)
	}
}

There you have it! What do you think? Have you got something better in mind?

Update turns out some of you found the n|(1<<i) > n method kind of gibberish and harder to understand than a &. So here’s the consequent change:

func btoflag(bf []bool, n int) {
	for i, _ := range bf {
		if n&(1<<i) != 0 {
			bf[i] = true
		}
	}
}

func main() {
	for i := 0; i < 32; i++ {
		bf := []bool{false, false, false, false, false}
		btoflag(bf, i)
		fmt.Println(bf)
	}
}

In this method, only if both bits are true then the field should be true. For example:

5 in base 10 (decimal) is 00101 in base 2 (binary) with 5 bits
4(10) is 00100

op 16 8 4 2 1
  0 0 1 0 1
& 0 0 1 0 0
= 0 0 1 0 0

When 5 is passed to btoflag(), 4 and 1 will match, but no other power of 2, thus, these two bits are set to true.