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