如何在Python中将字符串向右移动?

9

我尝试将字符串向右移动:

  • 最后一个值应该成为第一个,其余的依次向后
  • s= "I Me You" 应该返回 "You I Me"

我尝试了以下代码,但它不起作用,请帮我解决问题。

sr= "I Me You"
def shift_right(sr):
    L=sr.split()
    new_list=L[-1]

    new_list= new_list.append(1,L[:0])
    return (new_list)

print(shift_right(sr)
print (shift_reverse(sr))

1
你的第一个问题是在print(shift_right(sr)这一行缺少了一个括号。你的第二个问题是append会直接修改列表,所以不需要使用new_list= - rlms
11个回答

9

现在是比赛时间。

比赛项目

也许更有趣的是“哪种方法更快?”

第一项测试使用OP测试字符串(仅有3个块),第二项测试使用600个单字符块的字符串。

from collections import deque
import timeit

def trivial(s):
    l = s.split()
    return ' '.join(l[-1:] + l[:-1])

def more_split(s):
    return ' '.join([s.split()[-1]] + s.split()[:-1])

def dq(s):
    s_deq = deque(s.split())
    s_deq.rotate(1)
    return ' '.join(s_deq)

def find_and_slice(s):
    lsi = s.rfind(' ')
    return s[lsi+1:] + ' ' + s[:lsi]

def rs_lazy(s):
    return ' '.join(reversed(s.rsplit(maxsplit=1)))

def rs_smart(s):
    rs = s.rsplit(maxsplit=1)
    return rs[1] + ' ' + rs[0]

def rpart(s):
    part = s.rpartition(' ')
    return part[-1] + part[1] + part[0]

def time_a_method(m, s):
    c_arg = "('{}')".format(s)
    t = timeit.timeit(m + c_arg, setup="from __main__ import " + m , number=100000)
    print( m + " "*(15-len(m)) + "----> {}".format(t))


if __name__ == '__main__':
    print(trivial("I Me You"))
    print(more_split("I Me You"))
    print(dq("I Me You"))
    print(find_and_slice("I Me You"))
    print(rs_lazy("I Me You"))
    print(rs_smart("I Me You"))
    print(rpart("I Me You"))
    print("######## USE: 'I Me You'")
    for m in ["trivial", "more_split", "dq", "find_and_slice", "rs_lazy", "rs_smart", "rpart"]:
        time_a_method(m, "I Me You")

    print("######## USE: 'a b c d e f '*100")
    s = 'a b c d e f '*100
    for m in ["trivial", "more_split", "dq", "find_and_slice", "rs_lazy", "rs_smart", "rpart"]:
        time_a_method(m, s)

这将产生以下结果:
You I Me
You I Me
You I Me
You I Me
You I Me
You I Me
You I Me
######## USE: 'I Me You'
trivial        ----> 0.1339518820000194
more_split     ----> 0.1532761280000159
dq             ----> 0.182199565000019
find_and_slice ----> 0.07563322400005745
rs_lazy        ----> 0.23457759100006115
rs_smart       ----> 0.1615759960000105
rpart          ----> 0.06102836100001241
######## USE: 'a b c d e f '*100
trivial        ----> 3.2239098259999537
more_split     ----> 4.6946649449999995
dq             ----> 3.991058845999987
find_and_slice ----> 0.15106809200005955
rs_lazy        ----> 0.32278001499992115
rs_smart       ----> 0.22939544400003342
rpart          ----> 0.10590313199998036

获胜者是......

def rpart(s):
    part = s.rpartition(' ')
    return part[-1] + part[1] + part[0]

那让我感到惊讶(我打赌使用find_and_slice,但失败了)。有两个答案类别:
  1. 暴力法:将所有字符串分割
  2. 注意我们只需要字符串的最后一部分
即使在最简单的情况下 I Me You,第一种方法也比最佳方法慢2至3倍。显然,当字符串变得更加有趣时,第一种方法变得非常低效。
真正有趣的事情是,得票最高的答案竟然是最慢的 :)

不错的基准测试!这告诉我应该更多地使用rpartition。似乎rpartition会创建一个额外的元组对象,这是有成本的,但显然比在Python中执行两个显式切片的成本要低。 - Shashank
我已经更新了rsplit的解决方案,我相信这将比使用join和reversed更快。现在它更类似于rfind和partition的答案。 - Shashank
@Shashank 已更新... 但它并没有改变最终结果。 - Michele d'Amico
是的,我知道,我已经自己运行过了,rpartition和rfind仍然明显是最快的,但我认为避免使用reversed和join可以使某些东西快1.5倍,这仍然很有趣。 - Shashank

6
首先我们要拆分这个字符串:
>>> s = "I Me You"
>>> l = s.split()
>>> l
['I', 'Me', 'You']

然后我们将从最后一个元素到结尾的列表l[-1:]与从开头到(但不包括)最后一个元素的列表l[:-1]相加:

>>> l[-1:] + l[:-1]
['You', 'I', 'Me']

最后,我们加入:

>>> ' '.join(l[-1:] + l[:-1])
'You I Me'

2
更快的解决方案使用 str.rfind、字符串切片和字符串连接:

>>> s = 'I Me You'
>>> lsi = s.rfind(' ')
>>> s[lsi+1:] + ' ' + s[:lsi]
'You I Me'

另一个快速的解决方案是使用str.rsplit函数:
>>> rs = s.rsplit(maxsplit=1)
>>> rs[1] + ' ' + rs[0]
'You I Me'

在函数形式中:
def find_and_slice(s):
    lsi = s.rfind(' ')
    return s[lsi+1:] + ' ' + s[:lsi]

def rs(s):
    rs = s.rsplit(maxsplit=1)
    return rs[1] + ' ' + rs[0]

这不是期望的输出。 - Malik Brahimi
@MalikBrahimi 感谢您的通知,我已经修复了它以输出正确的结果。 - Shashank

2

如果您将字符串转换为 collections.deque,那么您可以使用 rotate() 方法:

from collections import deque

s = 'I Me You'
s_deq = deque(s.split())
s_deq.rotate(1)
print ' '.join(s_deq)
#OUT: You I Me

2
如果所有分隔符相同(split没有参数可以接受所有空白字符),则可以不使用列表来执行此操作。可以使用字符串方法,例如rindexrpartition
 >>> part = s.rpartition(' ')
 >>> part[-1] + part[1] + part[0]
 'You I Me'

1

这段代码适用于您

def shift_str(s):
    arr = s.split()
    first = arr.pop(0)
    arr.append(first)
    return " ".join(arr)

E.g:

shift_str("xxx ccc lklklk") >> 'ccc lklklk xxx'

shift_str("xxx ccc lklklk") 的返回结果应为 'ccc lklklk xxx'


OP提问的是右移而不是左移,这是错误的。 - Michele d'Amico

1
你可以使用索引和切片来创建一个新的列表,然后用空格将它们连接起来:
print(' '.join([s.split()[-1]] + s.split()[:-1])) # You I Me

1
s = "I Me You"

In [2]: s.rsplit(None, 1)[-1] + ' ' + s.rsplit(None, 1)[0]
Out[3]: "You I Me"

1
你可以使用.pop()
def shift(lst, side):
    if side == "left":
        a = lst.pop(0)
        return lst + [a]
    elif side == "right":
        a = lst.pop()
        return [a] + lst
    raise ValueError("Side is incorrect: " + side)

0
def shift_right(sr):
    L = sr.split()
    return ' '.join([L[-1]]+L[:-1])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接