有没有办法简化所有可能(长 x 高)网格的创建?

Is there a way to simplify the creation of all possible (length x height) grids?

这是我的 4x4 网格代码,可以更好地解释我的问题:

    #The "Duct-Tape" solution
    for box0 in range(0,2):
        for box1 in range(0,2):
            for box2 in range(0,2):
                for box3 in range(0,2):
                    for box4 in range(0,2):
                        for box5 in range(0,2):
                            for box6 in range(0,2):
                                for box7 in range(0,2): #0 = OutBag, 1 = InBag
                                    for box8 in range(0,2):
                                        for box9 in range(0,2):
                                            for box10 in range(0,2):
                                                for box11 in range(0,2):
                                                    for box12 in range(0,2):
                                                        for box13 in range(0,2):
                                                            for box14 in range(0,2):
                                                                for box15 in range(0,2):
                                                                    totalGrids.append([[box0,box1,box2,box3],
                                                                                         [box4,box5,box6,box7],
                                                                                         [box8,box9,box10,box11],
                                                                                         [box12,box13,box14,box15]])

有什么方法可以制作长 x 高大小的网格?

这是另一种通过使用二进制算术以更少 for 循环完成此操作的方法:

totalGrids = []
for i in range(0, 1 << 16):
    totalGrids.append(
        [
            [(i >> j) & 1 for j in range(0, 4)], 
            [(i >> j) & 1 for j in range(4, 8)], 
            [(i >> j) & 1 for j in range(8, 12)], 
            [(i >> j) & 1 for j in range(12, 16)]
        ])
print(totalGrids[0])
print(totalGrids[1])
print(totalGrids[2])
print()
print(totalGrids[-3])
print(totalGrids[-2])
print(totalGrids[-1])

输出(前 3 个和后 3 个元素):

[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
[[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
[[0, 1, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]

[[1, 0, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
[[0, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]

要将其从 4 x 4 概括为 height x width,类似这样的方法应该可行:

height = 3
width = 5
totalGrids = []
for i in range(0, 1 << (height * width)):
    totalGrids.append(
        [[(i >> j) & 1 for j in range(k * width, (k + 1) * width)] for k in range(0, height)]
    )

这里对上面的内容进行解释。

  • 包含 height x width 个元素的矩阵将在这些元素中填充 0 和 1 的所有可能组合。举个例子,如果height = 2,width = 4,那么一共有8个元素,需要的0和1组合的一种排序是:
0 0 0 0   0 0 0 0 (this is 0 in binary)
0 0 0 0   0 0 0 1 (this is 1 in binary)
0 0 0 0   0 0 1 0 (this is 2 in binary)
0 0 0 0   0 0 1 1 (this is 3 in binary)
...
0 0 0 0   1 1 1 1 (this is 15 in binary)
0 0 0 1   0 0 0 0 (this is 16 in binary)
0 0 0 1   0 0 0 1
0 0 0 1   0 0 1 0
0 0 0 1   0 0 1 1 (EXAMPLE VALUE USED BELOW)
...
0 0 1 0   0 0 0 0 (this is 32 in binary)
...
0 0 1 1   0 0 0 0 (this is 48 in binary)
...
1 1 1 1   1 1 1 1 (this is 255 = 2**8 - 1 in binary)

这些只是从0到2**8 - 1的二进制值,可以表示为range(0, 2**8)中的Python个整数。它们正是所需要的,现在唯一的问题是如何填充大小为 height x width.[=64 的 Python list of lists =]

答案是用二进制算术。让我们以 0 0 0 1 0 0 1 1 为例。我们可以在Python中指定这个为整数,即i = 19.

对于 8 的 1st 槽,我们希望在我们的示例中使用最右边的二进制位,即 1。我们可以使用 Python 的按位 & 运算通过 value = i & 1 来提取它。将 & 1 应用于任何整数都有效地屏蔽了二进制 ones-place 数字以外的所有数字。

对于2nd插槽,我们需要添加一个额外的步骤:

  • 首先我们将位向右滑动 1 个位置(允许最右边的位从边缘脱落,这很好,因为我们已经处理过它并且不再需要它)使用 Python的right shift操作>>如下:value = i >> 1。在二进制中,这会产生 0 0 0 0 1 0 0 1,即整数 9。right-shift 运算符将二进制 twos-place 中的位向右移动到二进制 ones-place.
  • 接下来,我们可以使用与 1st 插槽相同的技术来屏蔽除 ones-place 位以外的所有位:value = i & 1.
  • 我们可以简单地写成:value = (i >> 1) & 1.
  • 而不是将上面的语句作为两个单独的语句来执行

一般来说,对于 j'th 槽,我们可以从我们的示例整数中提取 j'th 位,方法是编写:value = (i >> j) & 1.

现在让我们看看循环中的关键逻辑:

[[(i >> j) & 1 for j in range(k * width, (k + 1) * width)] for k in range(0, height)]

这使用嵌套的 list comprehension 首先在 range(0, height) 中遍历 k,然后在 range(k * width, (k + 1) * width) 中遍历 j,并将结果放入将上述按位表达式 (i >> j) & 1 放入矩阵中的每个连续元素(或 listslist)。

最后,我们再看一下代码中最外层的循环:

for i in range(0, 1 << (height * width)):

这使用了Python的按位left shift运算<<,它做的与right shift (>>)相反,即移位1 的位向左 (height * width) 个二进制位置。因为每次向左移动都会导致数字的值加倍,所以我们的 left shift 表达式给出与 2 ** (height * width) 相同的结果,这正是您的问题正在寻找的 0/1 组合的数量。

因此,通过从 0 迭代到 2 **(高度 * 宽度),然后提取每个值的位并将其整理到该迭代矩阵的相应矩阵元素中,并将该矩阵附加到 totalGrids 变量,我们最终构建了一个具有所需属性的矩阵列表。