繁体   English   中英

Python将(多个)字符串连接到数字

[英]Python concatenate (multiple) strings to number

我有一个 python 列表['a1', 'b1', 'a2', 'b2','a3', 'b3'] 设置m=3并且我想使用循环获取此列表,因为这里m=3可能是一个更大的数字,例如m=100

因为我们可以有

m = 3

['a' + str(i) for i in np.arange(1,m+1)]
# ['a1', 'a2', 'a3']

['b' + str(i) for i in np.arange(1,m+1)]
# ['b1', 'b2', 'b3']

然后我尝试使用['a1', 'b1', 'a2', 'b2','a3', 'b3']

[ ['a','b'] + str(i) for i in np.arange(1,m+1)]

并且有TypeError: can only concatenate list (not "str") to list

然后我尝试

[ np.array(['a','b']) + str(i) for i in np.arange(1,m+1)]

而且我仍然收到错误,因为UFuncTypeError: ufunc 'add' did not contain a loop with signature matching types (dtype('<U1'), dtype('<U1')) -> None

我该如何解决这个问题? 更重要的是,如何通过类似的方式获得类似['a1', 'b1', 'c1', 'a2', 'b2','c2','a3', 'b3', 'c3']东西?

您需要对数字范围和字符串列表进行迭代

In [106]: [s+str(i) for i in range(1,4) for s in ['a','b']]
Out[106]: ['a1', 'b1', 'a2', 'b2', 'a3', 'b3']

正如@j1-lee 的答案(以及稍后在其他答案中)所指出的那样,一个简单的组合list理解将起作用。

import string


def letter_number_loop(n, m):
    letters = string.ascii_letters[:n]
    numbers = range(1, m + 1)
    return [f"{letter}{number}" for number in numbers for letter in letters]

类似地,可以使用itertools.product() ,正如尼克的回答所证明的那样,获得基本相同的结果:

import itertools


def letter_number_it(n, m):
    letters = string.ascii_letters[:n]
    numbers = range(1, m + 1)
    return [
        f"{letter}{number}"
        for number, letter in itertools.product(numbers, letters)]

但是,可以编写 NumPy 向量化方法,利用如果dtypeobject的事实,则操作确实遵循 Python 语义。

import numpy as np


def letter_number_np(n, m):
    letters = np.array(list(string.ascii_letters[:n]), dtype=object)
    numbers = np.array([f"{i}" for i in range(1, m + 1)], dtype=object)
    return (letters[None, :] + numbers[:, None]).ravel().tolist()

请注意,如果消耗输出的任何东西都能够处理 NumPy 数组本身,则可以避免最终的numpy.ndarray.tolist() ,从而节省一些相对较小但绝对可观的时间。


检查输出

以下确实表明这些功能是等效的:

funcs = letter_number_loop, letter_number_it, letter_number_np

n, m = 2, 3
for func in funcs:
    print(f"{func.__name__!s:>32}  {func(n, m)}")
              letter_number_loop  ['a1', 'b1', 'a2', 'b2', 'a3', 'b3']
                letter_number_it  ['a1', 'b1', 'a2', 'b2', 'a3', 'b3']
                letter_number_np  ['a1', 'b1', 'a2', 'b2', 'a3', 'b3']

基准

对于较大的输入,这要快得多,这些基准证明了这一点:

timings = {}
k = 16
for n in (2, 20):
    for k in range(1, 10):
        m = 2 ** k
        print(f"n = {n}, m = {m}")
        timings[n, m] = []
        base = funcs[0](n, m)
        for func in funcs:
            res = func(n, m)
            is_good = base == res
            timed = %timeit -r 64 -n 64 -q -o func(n, m)
            timing = timed.best * 1e6
            timings[n, m].append(timing if is_good else None)
            print(f"{func.__name__:>24}  {is_good}  {timing:10.3f} µs")

要绘制:

import matplotlib.pyplot as plt
import pandas as pd

n_s = (2, 20)
fig, axs = plt.subplots(1, len(n_s), figsize=(12, 4))
for i, n in enumerate(n_s):
    partial_timings = {k[1]: v for k, v in timings.items() if k[0] == n}
    df = pd.DataFrame(data=partial_timings, index=[func.__name__ for func in funcs]).transpose()
    df.plot(marker='o', xlabel='Input size / #', ylabel='Best timing / µs', ax=axs[i], title=f"n = {n}")

基准

这些表明显式循环版本( letter_number_loop()letter_number_it() )在某种程度上具有可比性,而 NumPy 向量化的( letter_number_np() )对于较大的输入相对更快,最高可达约 2 倍的加速。

列表理解中可以有多个for

prefixes = ['a', 'b', 'c']
m = 3

output = [f"{prefix}{num}" for num in range(1, m+1) for prefix in prefixes]
print(output) # ['a1', 'b1', 'c1', 'a2', 'b2', 'c2', 'a3', 'b3', 'c3']

如果你有多个for s,那些将被嵌套,如

for num in range(1, m+1):
    for prefix in prefixes:
        ...

您可以使用itertools.product获取字母和m范围的所有组合,然后将它们连接到 f 字符串中(而不是使用join ,因为一个元素是整数,因此需要转换为字符串):

[f'{x}{y}' for x, y in itertools.product(range(1, m+1), ['a', 'b'])]

输出:

['a1', 'b1', 'a2', 'b2', 'a3', 'b3']

暂无
暂无

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

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