简体   繁体   English

Python反向跨步切片

[英]Python reverse-stride slicing

A specific example of my question is, "How can I get '3210' in this example?"我的问题的一个具体例子是,“在这个例子中我怎样才能得到‘3210’?”


>>> 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'

It seems strange that I can write foo[4:0:-1], foo[5:1:-1], etc. and get what I would expect, but there's no way to write the slice so that I get '3210'.我可以写 foo[4:0:-1]、foo[5:1:-1] 等并得到我所期望的结果,这似乎很奇怪,但是没有办法编写切片以便得到 '3210 '。

A makeshift way of doing this would be foo[0:4][::-1], but this creates two string objects in the process.这样做的一种临时方法是 foo[0:4][::-1],但这会在此过程中创建两个字符串对象。 I will be performing this operation literally billions of times, so every string operation is expensive.我将执行此操作数十亿次,因此每个字符串操作都很昂贵。

I must be missing something silly and easy.我一定错过了一些愚蠢而简单的东西。 Thanks for your help!谢谢你的帮助!

Simply exclude the end range index...只需排除结束范围索引...

>>> foo[3::-1]
'3210'

Ironically, about the only option I think you didn't try.具有讽刺意味的是,关于我认为你没有尝试过的唯一选择。

Omit the end index in your slice notation:省略切片符号中的结束索引:

>>> foo = '0123456'
>>> foo[3::-1]
'3210'

If you have to do this many times, create a slice object that you can use over and over如果您必须多次这样做,请创建一个可以反复使用的切片对象

>>> i = slice(3,None,-1)
>>> foo[i]
'3210'

If you're looking for something a little more human-readable than extended slice notation:如果您正在寻找比扩展切片符号更易读的东西:

>>> foo = '0123456'
>>> ''.join(reversed(foo[0:4]))
'3210'

After reading the "technical documentation" ( here ) - specifically the sentence:阅读“技术文档”( 此处)后 - 特别是这句话:

If either bound is negative, the sequence's length is added to it.如果任一边界为负,则将序列的长度添加到其中。

I decided to try this, and it worked:我决定试试这个,它奏效了:

>>> foo = '0123456'
>>> foo[3:-1-len(foo):-1]
'3210'
>>>

So I think the best answer to programmatically determine the "end point" would be to provide a well named helper function that makes it clear that its arguments are always treated like positive offsets, maybe special_slice()所以我认为以编程方式确定“终点”的最佳答案是提供一个命名良好的辅助函数,它清楚地表明其参数始终被视为正偏移量,也许是special_slice()

I think the clarity of this 'special' case is extremely important since lots of common and significant use cases depend on the default behavior of negative offsets (ie adding the length to them).我认为这种“特殊”情况的清晰度非常重要,因为许多常见和重要的用例取决于负偏移的默认行为(即向它们添加长度)。 Personally I frequently use a '-1' end point to mean: stop just before last element.我个人经常使用“-1”结束点来表示:在最后一个元素之前停止。

So, based on your comment:因此,根据您的评论:

... algorithm that works somewhat like as follows: foo[i:i-4:-1], and starts with a high 'i' and walks down. ... 算法的工作原理如下: foo[i:i-4:-1],并以高位 'i' 开始并向下走。

I might make the following:我可能会做以下事情:

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]

And then call it for each slice required:然后为每个所需的切片调用它:

foo_part = slice_by_len(foo, i, 4, -1)

The above could easily go in a loop over values of 'i'以上可以很容易地循环遍历 'i' 的值

You can use s[::-1] to reverse the entire string.您可以使用s[::-1]来反转整个字符串。 But if you want to reverse each substring with some fixed length, you can first extract the substring and then reverse the entire substring.但是如果你想反转每个固定长度的子串,你可以先提取子串,然后反转整个子串。 For example, let's assume we need to check whether each substring with length 3 of string foo is a palindrome, we can do it like this:例如,假设我们需要检查字符串foo每个长度为 3 的子字符串是否是回文,我们可以这样做:

>>> 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

If you want to check if a substring is palindrome like this:如果你想检查一个子串是否是这样的回文:

if foo[i:i+3] == foo[i+2:i-1:-1]:
    ...

you will not be able to handle the case of i being 0 , since you are actually comparing foo[0:3] with foo[2:-1:-1] , which is equivalent to foo[2:n-1:-1] , which in turn is an empty string.您将无法处理i0的情况,因为您实际上是在将foo[0:3]foo[2:-1:-1] ,这相当于foo[2:n-1:-1] ,这又是一个空字符串。

The only drawback of the first solution is that it uses a little more memory but it's no big deal.第一个解决方案的唯一缺点是它使用了更多的内存,但这没什么大不了的。

In addition to the above solutions, you can do something like:除了上述解决方案,您还可以执行以下操作:

foo = '0123456'
foo[-4::-1]

I guess if foo is going to be changing lengths, this may not be the best solution, but if the length is static it would work.我想如果 foo 会改变长度,这可能不是最好的解决方案,但如果长度是静态的,它会起作用。

Given:鉴于:

>>> foo = '0123456'

The desired string 3210 is from index 3rd to the 0-th characters:所需的字符串3210是从索引 3rd 到第 0 个字符:

>>> stop_idx=0
>>> start_idx=3

Here are two generic solutions:这里有两个通用的解决方案:

  1. Take the forward slice then reverse it:取前向切片然后反转它:

     >>> foo[stop_idx:start_idx+1][::-1] '3210'
  2. Based on this answer , use a negative step and stop 1 element before the first element (plus the stop offset):基于此答案,在第一个元素之前使用负步并停止 1 个元素(加上停止偏移量):

     >>> foo[start_idx:stop_idx-len(foo)-1:-1] '3210' >>> a[start_idx:stop_idx-len(a)-1:-1] [2, 1]

Comparing execution times, the first version is faster:比较执行时间,第一个版本更快:

>>> 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
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))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM