【问题标题】:Python Swap two digits in a number?Python交换数字中的两位数字?
【发布时间】:2012-10-23 23:32:41
【问题描述】:

在 Python 中交换两个数字的最快方法是什么?我得到了字符串形式的数字,所以如果我能有这么快的东西就好了

string[j] = string[j] ^ string[j+1] 
string[j+1] = string[j] ^ string[j+1]
string[j] = string[j] ^ string[j+1]

我所见过的一切都比 C 语言中的要贵得多,并且涉及制作一个列表,然后将列表转换回来或其中的一些变体。

【问题讨论】:

  • 要交换哪些数字?
  • 这里你无法避免从和到可变类型的转换。您可以尝试使用array 模块,但我不能保证它会更快。
  • 你知道我
  • 来这里寻找很酷的数学解决方案,很失望地看到你的“数字”实际上只是一个字符串:(
  • @millimoose:如果不必就地进行交换,则可以避免转换为可变类型。

标签: python performance swap


【解决方案1】:

这比你想象的要快,至少比 Jon Clements 在我的计时测试中的当前答案快:

i, j = (i, j) if i < j else (j, i) # make sure i < j
s = s[:i] + s[j] + s[i+1:j] + s[i] + s[j+1:]

如果你想比较你得到的任何其他答案,这里是我的测试平台:

import timeit
import types

N = 10000
R = 3
SUFFIX = '_test'
SUFFIX_LEN = len(SUFFIX)

def setup():
    import random
    global s, i, j
    s = 'abcdefghijklmnopqrstuvwxyz'
    i = random.randrange(len(s))
    while True:
        j = random.randrange(len(s))
        if i != j: break

def swapchars_martineau(s, i, j):
    i, j = (i, j) if i < j else (j, i) # make sure i < j
    return s[:i] + s[j] + s[i+1:j] + s[i] + s[j+1:]

def swapchars_martineau_test():
    global s, i, j
    swapchars_martineau(s, i, j)

def swapchars_clements(text, fst, snd):
    ba = bytearray(text)
    ba[fst], ba[snd] = ba[snd], ba[fst]
    return str(ba)

def swapchars_clements_test():
    global s, i, j
    swapchars_clements(s, i, j)

# find all the functions named *SUFFIX in the global namespace
funcs = tuple(value for id,value in globals().items()
            if id.endswith(SUFFIX) and type(value) is types.FunctionType)

# run the timing tests and collect results
timings = [(f.func_name[:-SUFFIX_LEN],
            min(timeit.repeat(f, setup=setup, repeat=R, number=N))
           ) for f in funcs]
timings.sort(key=lambda x: x[1])  # sort by speed
fastest = timings[0][1]  # time fastest one took to run
longest = max(len(t[0]) for t in timings) # len of longest func name (w/o suffix)

print 'fastest to slowest *_test() function timings:\n' \
      ' {:,d} chars, {:,d} timeit calls, best of {:d}\n'.format(len(s), N, R)

def times_slower(speed, fastest):
    return speed/fastest - 1.0

for i in timings:
    print "{0:>{width}}{suffix}() : {1:.4f} ({2:.2f} times slower)".format(
                i[0], i[1], times_slower(i[1], fastest), width=longest, suffix=SUFFIX)

附录:

对于以字符串形式给出的正十进制数交换数字字符的特殊情况,以下方法也有效,并且比我答案顶部的一般版本快一点。

使用format() 方法在末尾转换回字符串有些复杂,用于处理将零移到字符串前面的情况。我主要把它作为一种好奇心来呈现,因为除非你掌握它在数学上的作用,否则它是相当难以理解的。它也不处理负数。

n = int(s)
len_s = len(s)
ord_0 = ord('0')
di = ord(s[i])-ord_0
dj = ord(s[j])-ord_0
pi = 10**(len_s-(i+1))
pj = 10**(len_s-(j+1))
s = '{:0{width}d}'.format(n + (dj-di)*pi + (di-dj)*pj, width=len_s)

【讨论】:

  • 这很可能是 OP 所追求的,因为他们希望稍后对结果进行哈希处理。
【解决方案2】:

它必须是某种可变类型,我能想到的最好的是(虽然不能对性能做出任何声明):

def swapchar(text, fst, snd):
    ba = bytearray(text)
    ba[fst], ba[snd] = ba[snd], ba[fst]
    return ba

>>> swapchar('thequickbrownfox', 3, 7)
bytearray(b'thekuicqbrownfox')

您仍然可以将结果用作 str/list - 或在需要时将其显式转换为 str

【讨论】:

  • bytearray(b'thekuicqbrownfox') 有没有一种从 bytearray 到 string 的快速方法?
  • @EnderX 感谢您的更正-我拥有的原始代码,其中包含return str(ba)...这将是我所知道的获得真正str 类型返回的最快方法,但在大多数情况下,您可以将bytearray 视为str
  • 好的,谢谢,我需要它作为 str,因为我必须在之后对其进行哈希处理。
【解决方案3】:


    >>> int1 = 2
    >>> int2 = 3
    >>> eval(str(int1)+str(int2))
    23

【讨论】:

    【解决方案4】:

    我知道你已经接受了一个答案,所以我不会费心用 Python 编写它,但是你可以在 JavaScript 中这样做,它也有不可变的字符串:

    function swapchar(string, j)
    {
        return string.replace(RegExp("(.{" + j + "})(.)(.)"), "$1$3$2");
    }
    

    很明显,如果j 不在适当的范围内,那么它只会返回原始字符串。

    【讨论】:

      【解决方案5】:

      给定一个整数n 和两个(从零开始的)索引ij 要交换的数字,这可以使用十的幂来定位数字、除法和模运算来提取它们,以及执行交换的减法和加法。

      def swapDigits(n, i, j):
          # These powers of 10 encode the locations i and j in n.
          power_i = 10 ** i
          power_j = 10 ** j
      
          # Retrieve digits [i] and [j] from n.
          digit_i = (n // power_i) % 10
          digit_j = (n // power_j) % 10
      
          # Remove digits [i] and [j] from n. 
          n -= digit_i * power_i
          n -= digit_j * power_j
      
          # Insert digit [i] in position [j] and vice versa.
          n += digit_i * power_j
          n += digit_j * power_i
      
          return n
      

      例如:

      >>> swapDigits(9876543210, 4, 0)
      9876503214
      >>> swapDigits(9876543210, 7, 2)
      9826543710
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-10-01
        • 1970-01-01
        • 1970-01-01
        • 2022-11-04
        • 1970-01-01
        相关资源
        最近更新 更多