【问题标题】:How to wrap a string or an array around and slice the wrapped string or array in Python?如何在 Python 中包装字符串或数组并切片包装的字符串或数组?
【发布时间】:2018-07-15 12:00:49
【问题描述】:

在任何事情之前:我确实阅读了Wrapping around a python list as a slice operationwrapping around slices in Python / numpy

这个问题与这两个问题中的任何一个都不是重复的,因为这个问题是一个完全不同的问题。因此,请停止投票,不要将其标记为重复。在第一个提到的线程中,那里的“包装”意味着不同的东西。对于第二个提到的线程,他们处理的是 ndarray 并且只能用于整数。

真正的问题: 如何将字符串或数组从一个点切片到另一个点,并在它们之间有一个端点?

本质上,我们想做这样的事情,

n = whatever we want
print(string[n-5:n+6])

上面的代码可能看起来很正常。但它在边缘附近不起作用(靠近字符串/数组的开头或字符串/数组的结尾)。因为 Python 的切片不允许从数组的末尾切片并从头开始。如果 n 小于 5 或​​字符串长度大于 n+6 怎么办?

这是一个更好的例子,考虑到我们有

array = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k']

我们想为数组中的所有元素打印一个元素及其最近的两个邻居字符串

print("Two neighbors:")
for i, x in enumerate(array):
    print(array[i-1] + array[i] + array[(i+1)%len(array)])

输出:

Two neighbors:
kab
abc
bcd
cde
def
efg
fgh
ghi
hij
ijk
jka

到目前为止一切顺利,让我们和四个邻居一起做吧。

print("Four neighbors:")
for i, x in enumerate(array):
    print(array[i-2] + array[i-1] + array[i] + array[(i+1)%len(array)] + array[(i+2)%len(array)])

输出:

Four neighbors:
jkabc
kabcd
abcde
bcdef
cdefg
defgh
efghi
fghij
ghijk
hijka
ijkab

您可以看到这是怎么回事,随着所需邻居数量的增加,我们必须逐一输入它们的次数增加。

有没有办法代替s[n-3]+s[n-2]+s[n-1]+s[n]+s[n+1]+s[n+2]+s [n+3],我们可以做类似 s[n-3:n+4] 的事情吗?

请注意,s[n-3:n]+s[n:(n+4)%len(s)] 在边缘不起作用。

注意:

对于上面的特定示例,可以做一个 3*array 或在前面和后面添加一些元素以基本上“填充”它。

但是,这种类型的答案会占用一些内存,并且当我们想要将其折叠很多次时无法工作。

考虑以下,

# len(string) = 10
# n = 0 or any number we want
print(string[n-499:n+999])

如果开始和结束索引可以灵活而不是相互镜像(例如,string[n-2:n+9] 而不是 string[n-3:n+4]),那就更好了。

【问题讨论】:

  • 我会这样做: (3*array)[len(array)+ni:len(array)+n+i+1] 其中 n 是中间索引,i 是每边所需的邻居数。
  • @BUZZY 我做了几乎相同的解决方法,只需在开头和结尾添加 i 数字,然后将 i 添加到所需的索引。这样可以节省更多内存。但是你和我的解决方法都不够 Pythonic。

标签: python arrays list


【解决方案1】:

不占用过多内存的解决方案如下

my_list = [1, 2, 3, 4, 5, 6, 7, 8, 9]

def get_sequences(a_list, sequence_length):
    sequences = []
    for i in range(len(my_list)):
        sequences.append("".join(str(my_list[(x + i) % len(my_list)]) for x in range(sequence_length)))
    return sequences

print(get_sequences(my_list, 2))
print(get_sequences(my_list, 3))

会输出

['12', '23', '34', '45', '56', '67', '78', '89', '91']
['123', '234', '345', '456', '567', '678', '789', '891', '912']

这很好,因为它可以在任何地方使用生成器。

【讨论】:

  • 完美答案。可以修改以使开始和结束灵活,易于阅读,非常 Pythonic 风格,内存高效并且本质上能够具有无限折叠。只是一个额外的,如果我想让它前面有2个邻居,后面有5个邻居(灵活切片),你会怎么写?
【解决方案2】:

这可以提供一些想法。唯一要检查的是间隔中的顺序。适用于任何n

array = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k']

def print_neighbors(n_neighbors):
    for idx in range(len(array)):
        start = (idx- n_neighbors//2) % len(array)
        end = (idx+n_neighbors//2) % len(array) + 1
        if start > end:
            print(''.join(array[start:] + array[:end]))
        else:
            print(''.join(array[start:end]))

>>> print_neighbors(6)

ijkabcd
jkabcde
kabcdef
abcdefg
bcdefgh
cdefghi
defghij
efghijk
fghijka
ghijkab
hijkabc

【讨论】:

  • 不错的经典答案,开头和结尾都灵活易懂。尽管我最初想避免使用条件语句,但仅比较索引就非常容易阅读。一直想知道为什么原生切片不这样做。
  • @Sayyora 这个解决方案效率低下,因为它依赖于if/else。这里的if/else会导致CPU中的分支预测错误,你可以通过循环完全解决这个问题。
  • @NickChapman 是的,如果可能的话,我也想避免使用条件语句。请参阅我的其他评论:通过在前面和后面添加 i 元素,我们基本上可以“包裹”数组。但是,这需要一些记忆。而且,如果我们想将它“包裹”一百倍,它是行不通的。将添加到问题。
  • @Sayyora 如果您正在寻找内存效率,我相信我的答案就是这样。
【解决方案3】:

您可以像这样创建一个类来包装您的原始可迭代对象:

class WrappingIterable():
     def __init__(self, orig):
         self.orig=orig
     def __getitem__(self, index):
         return self.orig[index%len(self.orig)]
     def __len__(self):
         return len(self.orig)


>>> w = WrappingIterable("qwerty")
>>> for i in range(-2, 8):
...     print(w[i])
t
y
q
w
e
r
t
y
q
w

【讨论】:

    【解决方案4】:

    对于这个特定的问题,您可以使用这样的 sn-p:

    def print_neighbors(l, n):
       wrapped = l[-(n//2):] + l + l[:(n//2)]
       for i in range(len(l)):
         print(''.join(wrapped[i:i+n+1]))
    
    l = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k']
    print_neighbors(l, 2)
    print_neighbors(l, 4)
    

    希望它有意义!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-12-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-29
      • 1970-01-01
      • 2017-04-19
      • 2022-01-01
      相关资源
      最近更新 更多