簡體   English   中英

在 Python 中從字符表達式創建列表的優雅方式

[英]Elegant way of creating list from character expression in Python

我有一個月份列表,如下所示,其中月份always用連字符分隔。

l = ['201701-201703', '201801-201804']

我想擴展列表以包括此范圍months的每個月。

期望的輸出應該是

['201701','201702','201703','201801','201802','201803','201804']

我的解決方案:

l1 = [[str(a) for a in list(map(lambda x:x+int(i[0:6]),list(range(abs(eval(i))+1))))] for i in l]
print(l1)
    [['201701', '201702', '201703'], ['201801', '201802', '201803', '201804']]

# Flatten the list
l2 = [item for sublist in l1 for item in sublist]
print(l2)
    ['201701', '201702', '201703', '201801', '201802', '201803', '201804']

我的解決方案閱讀起來非常麻煩,並且當范圍跨越多年時會失敗。 有人可以推薦一個更易於閱讀和理解的代碼嗎?

更新:如果最終結果是日期,那也沒關系。

以下是我使用pandas處理此問題的方法:

df = pd.DataFrame(l, columns=['date'])

# split start and end date into two columns and parse as datetime
df_ = df.date.str.split('-', expand=True).apply(pd.to_datetime, format='%Y%m')

# add MonthEnd -> this will ensure that the last month is included in the range
df_[1] = df_[1] + pd.offsets.MonthEnd()

# use pd.daterange to generate the range with a frequence of a month
(df_.apply(lambda x: pd.date_range(*x, freq='1M', closed='right'), axis=1)
                                    .explode()
                                    .dt.strftime('%Y%m')
                                    .values.tolist())

# ['201701', '201702', '201703', '201801', '201802', '201803', '201804']

希望它更具可讀性。

我將第二個表達式的大小增加了 5 個字符,但將第一個表達式的大小減少了 26 個字符。

刪除了map()list()abs()lambdaeval() 引入split()enumerate()

l = ['201701-201703', '201801-201804']
l1 = [range(*[int(v)+i for i,v in enumerate(e.split('-'))]) for e in l]
print(l1)
l2 = [str(item) for sublist in l1 for item in sublist]
print(l2)

輸出:

[range(201701, 201704), range(201801, 201805)]
['201701', '201702', '201703', '201801', '201802', '201803', '201804']

更新1

本次修改跳到了當年的境界。

l = ['201711-201802', '201901-201904']
l1 = [range(*[int(v)+i for i,v in enumerate(e.split('-'))]) for e in l]
print(l1)
l2 = [str(item) for sublist in l1 for item in sublist if 0 < item % 100 < 13]
print(l2)

輸出:

[range(201711, 201803), range(201901, 201905)]
['201711', '201712', '201801', '201802', '201901', '201902', '201903', '201904']

你可以這樣做:

[ str(q) for p in l for q in range(int(p[:6]), int(p[7:])+1) ]

但是,這不適用於從一年開始到下一年結束的范圍。 為此,您可以這樣做:

from datetime import datetime
from dateutil.relativedelta import relativedelta

l = ['201701-201703', '201801-201804', '201701-201804']

res_list = []
for p in l:
    d1 = datetime.strptime(p[:6], '%Y%m')
    d2 = datetime.strptime(p[7:], '%Y%m')
    while d1 <= d2:
        res_list.append(d1.strftime('%Y%m'))
        d1 += relativedelta(months=1)

res_list

輸出:

['201701',
 '201702',
 '201703',
 '201801',
 '201802',
 '201803',
 '201804',
 '201701',
 '201702',
 '201703',
 '201704',
 '201705',
 '201706',
 '201707',
 '201708',
 '201709',
 '201710',
 '201711',
 '201712',
 '201801',
 '201802',
 '201803',
 '201804']

您可以對列表理解做同樣的事情,但它不再優雅了。 但只是為了好玩,給你:

[ str(date)
  for d1, d2 in map(lambda p: map(int, p.split("-")), l) 
  for year_offset in range((d2 - d1)//100 +1)
  for date in range(max(d1, 100*(d1//100 + year_offset) +1 ), 
                    min(d2, 100*(d1//100 + year_offset) +12) +1) ]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM