Python reverse-stride slicing
我的问题的一个具体例子是,"在这个例子中,我怎样才能得到‘3210’。"
1 2 3 4 5 6 7 8 9 10 11 | >>> foo = '0123456' >>> foo[0:4] '0123' >>> foo[::-1] '6543210' >>> foo[4:0:-1] # I was shooting for '3210' but made a fencepost error, that's fine, but... '4321' >>> foo[3:-1:-1] # How can I get '3210'? '' >>> foo[3:0:-1] '321' |
我能写foo[4:0:-1]、foo[5:1:-1]等,并得到我所期望的,这似乎很奇怪,但没有办法写这个切片,所以我得到了"3210"。
这样做的一种临时方法是foo[0:4][::-1],但这会在进程中创建两个字符串对象。我将执行这个操作几十亿次,所以每个字符串操作都是昂贵的。
我一定错过了一些愚蠢和容易的事情。谢谢你的帮助!
只需排除结束范围索引…
1 2 | >>> foo[3::-1] '3210' |
讽刺的是,我认为你没有尝试过的唯一选择。
如果您在寻找比扩展切片符号更易于阅读的东西:
1 2 3 | >>> foo = '0123456' >>> ''.join(reversed(foo[0:4])) '3210' |
省略切片符号中的结束索引:
1 2 3 | >>> foo = '0123456' >>> foo[3::-1] '3210' |
如果必须多次执行此操作,请创建一个可反复使用的切片对象。
1 2 3 | >>> i = slice(3,None,-1) >>> foo[i] '3210' |
阅读"技术文档"(此处)-特别是以下句子:
If either bound is negative, the sequence’s length is added to it.
我决定试试这个,它奏效了:
1 2 3 4 | >>> foo = '0123456' >>> foo[3:-1-len(foo):-1] '3210' >>> |
因此,我认为以编程方式确定"端点"的最佳答案是提供一个名为helper的函数,它清楚地表明,它的参数总是被视为正偏移,可能是
我认为这个"特殊"案例的清晰性非常重要,因为许多常见和重要的用例都依赖于负偏移的默认行为(即向它们添加长度)。就我个人而言,我经常用一个"-1"结束点来表示:在最后一个元素之前停止。
因此,根据您的评论:
... algorithm that works somewhat like as follows: foo[i:i-4:-1], and starts with a high 'i' and walks down.
我可以这样做:
1 2 3 4 5 6 | def slice_by_len(data, start, length, step=1): end = start + length if step > 0 else start - length if end < 0: # Fix the negative offset to get what we really want end -= len(data) return data[start:end:step] |
然后对所需的每个切片调用它:
1 | foo_part = slice_by_len(foo, i, 4, -1) |
以上可以很容易地在"i"值上形成循环。
可以使用
1 2 3 4 5 6 7 8 9 10 11 12 | >>> foo = '0102030' >>> for i in range(len(foo)-3): ... if foo[i:i+3] == foo[i:i+3][::-1]: ... print(foo[i:i+3], 'is a palindrome') ... else: ... print(foo[i:i+3], 'is not a palindrome') ... 010 is a palindrome 102 is not a palindrome 020 is a palindrome 203 is not a palindrome 030 is a palindrome |
如果要检查子字符串是否是这样的回文:
1 2 | if foo[i:i+3] == foo[i+2:i-1:-1]: ... |
您将无法处理
第一个解决方案的唯一缺点是它使用了更多的内存,但这没什么大不了的。
除上述解决方案外,您还可以执行以下操作:
1 2 | foo = '0123456' foo[-4::-1] |
我想如果foo要改变长度,这可能不是最好的解决方案,但是如果长度是静态的,它会起作用。
鉴于:
1 | >>> foo = '0123456' |
所需的字符串
1 2 | >>> stop_idx=0 >>> start_idx=3 |
以下是两种通用解决方案:
向前切片,然后反转:
1 2 | >>> foo[stop_idx:start_idx+1][::-1] '3210' |
基于此答案,在第一个元素(加上停止偏移量)之前使用负的步骤并停止1个元素:
1 2 3 4 5 | >>> foo[start_idx:stop_idx-len(foo)-1:-1] '3210' >>> a[start_idx:stop_idx-len(a)-1:-1] [2, 1] |
比较执行时间,第一个版本更快:
1 2 3 4 | >>> timeit.timeit('foo[stop_idx:start_idx+1][::-1]', setup='foo="012345"; stop_idx=0; start_idx=3', number=10_000_000) 1.7157553750148509 >>> timeit.timeit('foo[start_idx:stop_idx-len(foo)-1:-1]', setup='foo="012345"; stop_idx=0; start_idx=3', number=10_000_000) 1.9317215870250948 |
1 2 3 4 5 6 7 | s="this is my world" pattern=re.findall(r'\S+',s) a=[] for i in range(len(pattern)): a.append((pattern[i][::-1])) print (a) print ("".join(a)) |