如何在 Python 中获取带有环绕的子列表

How can I get a sublist with wraparound in Python

提问人:Tim Kuipers 提问时间:2/17/2023 最后编辑:Kelly BundyTim Kuipers 更新时间:2/18/2023 访问量:90

问:

简单的一维案例

我想得到一个带环绕的子字符串。

str = "=Hello community of Python="
#      ^^^^^               ^^^^^^^  I want this wrapped substring

str[-7]
> 'P'

str[5]
> 'o'

str[-7:5]
> ''

为什么这个序列切片从负索引开始,以正索引结束,结果是一个空字符串?

我如何让它输出“Python==Hell”?


更高尺寸的案例

在这个简单的情况下,我可以做一些剪切和粘贴,但在我的实际应用中,我想得到一个更大网格的 2x2 大小的每个子网格 - 带有环绕。

m = np.mat('''1 2 3; 
              4 5 6; 
              7 8 9''')

我想让所有子矩阵都集中在某个位置,包括 。索引 with 不起作用 ,也不起作用(x, y)'9 7; 3 1'm[x-1:y+1](x,y)=(0,0)(x,y)=(1,0)7 8; 1 2

3D示例

m3d = np.array(list(range(27))).reshape((3,3,3))
>
array([[[ 0,  1,  2],
        [ 3,  4,  5],
        [ 6,  7,  8]],

       [[ 9, 10, 11],
        [12, 13, 14],
        [15, 16, 17]],

       [[18, 19, 20],
        [21, 22, 23],
        [24, 25, 26]]])

m3d[-1:1,-1:1,-1:1]
# doesn't give [[[26, 24], [20, 18]], [8, 6], [2, 0]]]

如果需要,我可以编写一些代码来获取各种子矩阵并将它们粘合在一起,但是当我必须将相同的方法应用于 3d 数组时,这种方法可能会变得非常麻烦。

我希望会有一个简单的解决方案。也许 numpy 可以在这里提供帮助?

python list slice numpy-slicing

评论

0赞 treuss 2/17/2023
为什么这个序列切片从负索引开始,以正索引结束,结果是一个空字符串?这与正/负无关,而是范围的下限 (-7 == 7) 大于上限 (5)。
2赞 Riccardo Bucco 2/17/2023
您能提供更多更高维度案例的例子吗?就像 2d 和 3d 一样。输入到底是什么,预期输出是什么?
0赞 Tim Kuipers 2/17/2023
@RiccardoBucco更新的说明
0赞 Kelly Bundy 2/17/2023
您是否真的需要负指数,或者大于规模的指数也就足够了?就像尝试用 获取所有子字符串一样。for i in range(len(s)): print(s[i:i+3])
1赞 Kelly Bundy 2/18/2023
@hpaulj“你必须选择两个部分并将它们连接起来”——我想说我的第一个答案反驳了这一点。

答:

0赞 treuss 2/17/2023 #1

只需自己将两半组合起来:

>>> str[-7:]+str[:5]
'Python==Hell'

评论

1赞 Tim Kuipers 2/17/2023
对于更高维的情况,例如在3D阵列中,这将如何工作?
0赞 Kelly Bundy 2/17/2023 #2

您可以充分重复您的数据,这样您就不需要环绕。

长度为 3 的子字符串:

s = 'Python'
r = 3

s2 = s + s[:r-1]
for i in range(len(s)):
    print(s2[i:i+r])

输出:

Pyt
yth
tho
hon
onP
nPy

大小为 2×2 的子矩阵:

import numpy as np

m = np.mat('''1 2 3; 
              4 5 6; 
              7 8 9''')
r = 2

m2 = np.tile(m, (2, 2))
for i in range(3):
    for j in range(3):
        print(m2[i:i+r, j:j+r])

输出(在线尝试!

[[1 2]
 [4 5]]
[[2 3]
 [5 6]]
[[3 1]
 [6 4]]
[[4 5]
 [7 8]]
[[5 6]
 [8 9]]
[[6 4]
 [9 7]]
[[7 8]
 [1 2]]
[[8 9]
 [2 3]]
[[9 7]
 [3 1]]

对于更大的多维数组,简单添加的 mmore 超出了必要的范围。您实际上只需要在每个维度上增加大小,而不是增加 .就像我对字符串所做的那样。不知道如何使用数组做到这一点。另外,我认为你也可以让你的负指数发挥作用,所以我们只需要有人来做这件事。np.tile+ r-1* 2

1赞 Kelly Bundy 2/17/2023 #3

使用高级索引(请参阅以“从 4x3 数组中选择角元素应使用高级索引”开头的部分):

import numpy as np

m = np.mat('''1 2 3; 
              4 5 6; 
              7 8 9''')

print(m[np.ix_(range(-1, 1), range(-1, 1))])
print(m[np.ix_(range(-2, 2), range(-2, 2))])
print(m[np.arange(-2, 2)[:, np.newaxis], range(-2, 2)])

输出(在线尝试!

[[9 7]
 [3 1]]
[[5 6 4 5]
 [8 9 7 8]
 [2 3 1 2]
 [5 6 4 5]]
[[5 6 4 5]
 [8 9 7 8]
 [2 3 1 2]
 [5 6 4 5]]

遍历所有子矩阵

由于您要遍历所有子矩阵,因此我们可以事先分别准备行范围和列范围,然后使用它们对来快速索引:

import numpy as np

A = np.mat('''1 2 3; 
              4 5 6; 
              7 8 9''')

m, n = A.shape

rowranges = [
    (np.arange(i, i+2) % m)[:, np.newaxis]
    for i in range(m)
]
colranges = [
    np.arange(j, j+2) % n
    for j in range(n)
]

for rowrange in rowranges:
    for colrange in colranges:
        print(A[rowrange, colrange])

输出(在线尝试!

[[1 2]
 [4 5]]
[[2 3]
 [5 6]]
[[3 1]
 [6 4]]
[[4 5]
 [7 8]]
[[5 6]
 [8 9]]
[[6 4]
 [9 7]]
[[7 8]
 [1 2]]
[[8 9]
 [2 3]]
[[9 7]
 [3 1]]

3D案例

m3d = np.array(list(range(27))).reshape((3,3,3))
m3d[np.ix_(range(-1,1), range(-1,1), range(-1,1))]

输出:

array([[[26, 24],
        [20, 18]],

       [[ 8,  6],
        [ 2,  0]]])

评论

0赞 Tim Kuipers 2/17/2023
该页面上有很多信息并不能直接帮助我解决问题。您可能希望将您想到的特定其他答案添加到您的解决方案中。尽管如此:这有效!谢谢。
1赞 Kelly Bundy 2/18/2023
@TimKuipers 现已添加。我更喜欢这种方式,因为它更简单。但另一种方式在实际程序中可能更快,因为您可以准备不同的行范围和不同的列范围,然后将它们配对并使用 .ix_m[rowrange, colrange]
0赞 Kelly Bundy 2/18/2023
@TimKuipers 现在将其添加为“遍历所有子矩阵”部分。
0赞 Tim Kuipers 2/18/2023
还有哪个?你复制整个数组的那个?听起来应该慢一点。
0赞 Kelly Bundy 2/18/2023
@TimKuipers你是说我的另一个答案?不,我在这个答案中指的是另一种方式。带有 .虽然。。。现在我正在考虑它......我的另一个答案实际上可能会更快(至少如果你只根据需要复制)。我认为这仍然是切片和创建视图,而这个答案中的高级索引会复制数据。话又说回来,当你实际使用子矩阵时,我想视图的访问速度会更慢。所以。。。我不知道。您必须使用实际用例测试不同的解决方案:-)np.newaxis