有没有办法简化所有可能(长 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
放入矩阵中的每个连续元素(或 lists
的 list
)。
最后,我们再看一下代码中最外层的循环:
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
变量,我们最终构建了一个具有所需属性的矩阵列表。
这是我的 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
xwidth
个元素的矩阵将在这些元素中填充 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
放入矩阵中的每个连续元素(或 lists
的 list
)。
最后,我们再看一下代码中最外层的循环:
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
变量,我们最终构建了一个具有所需属性的矩阵列表。