什么是最Python式的方式来排序日期序列?

2024-04-24 08:22:10 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个代表一年中一个月的刺痛列表(未排序,也不连续): ['1/2013', '7/2013', '2/2013', '3/2013', '4/2014', '12/2013', '10/2013', '11/2013', '1/2014', '2/2014']

我正在寻找一种Python式的方法来对它们进行分类,并将每个连续的序列分开,如下所示:

[ ['1/2013', '2/2013', '3/2013', '4/2013'], 
  ['7/2013'], 
  ['10/2013', '11/2013', '12/2013', '1/2014', '2/2014'] 
]

有什么想法吗?在


Tags: 方法列表排序分类代表序列
3条回答

groupby的例子很可爱,但过于密集,会在这个输入上中断:['1/2013', '2/2017'],也就是说,当有非相邻年份的相邻月份时。在

from datetime import datetime
from dateutil.relativedelta import relativedelta

def areAdjacent(old, new):
    return old + relativedelta(months=1) == new

def parseDate(s):
    return datetime.strptime(s, '%m/%Y')

def generateGroups(seq):
    group = []
    last = None
    for (current, formatted) in sorted((parseDate(s), s) for s in seq):
        if group and last is not None and not areAdjacent(last, current):
            yield group
            group = []
        group.append(formatted)
        last = current
    if group:
        yield group

结果:

^{pr2}$

如果您只想对列表进行排序,那么就使用sorted函数并传递keyvalue=a函数,该函数将日期字符串转换为Python的datetime对象,请检查下面的代码示例,将列表作为L

>>> from datetime import datetime
>>> sorted(L, key = lambda d: datetime.strptime(d, '%m/%Y'))
['1/2013', '2/2013', '3/2013', '7/2013', '10/2013', 
 '11/2013', '12/2013', '1/2014', '2/2014', '4/2014'] # indented by hand

要将“list of month/year strings”拆分为“list of continuous months”,您可以使用以下脚本(read comments),其中,我首先对列表L进行排序,然后根据连续月份对字符串进行分组(为了检查continuous month,我编写了一个函数):

^{pr2}$

其工作原理如下:

>>> is_cm('1/2012', '2/2012')
True # yes, consecutive
>>> is_cm('12/2012', '1/2013')
True # yes, consecutive
>>> is_cm('1/2015', '12/2012') # None --> # not consecutive
>>> is_cm('12/2012', '2/2013')
False # not consecutive

拆分代码的代码:

def result(dl):
    """
    dl: dates list - a iterator of 'month/year' strings
    type: list of strings

    returns: list of lists of strings
    """
    #Sort list:
    s_dl = sorted(dl, key=lambda d: datetime.strptime(d, '%m/%Y'))
    r_dl = [] # list to be return
    # split list into list of lists
    t_dl = [s_dl[0]] # temp list
    for d in s_dl[1:]:
        if not is_cm(t_dl[-1], d): # check if months are not consecutive
            r_dl.append(t_dl)
            t_dl = [d]
        else:
            t_dl.append(d)
    return r_dl

result(L)

别忘了包括from datetime import datetime,这个技巧我相信您可以很容易地更新一个新的日期列表,其中日期是其他格式的。在

在@9000提示之后,如果您想检查旧脚本check@codepad,我可以简化排序函数并删除旧答案。在

基于使用^{}the example from the docs that shows how to find runs of consecutive numbers

from itertools import groupby
from pprint import pprint

def month_number(date):
    month, year = date.split('/')
    return int(year) * 12 + int(month)

L = [[date for _, date in run]
     for _, run in groupby(enumerate(sorted(months, key=month_number)),
                           key=lambda (i, date): (i - month_number(date)))]
pprint(L)

解决方案的关键是与enumerate()生成的范围进行差分,以便连续的月份都出现在同一组中(run)。

输出

^{pr2}$

相关问题 更多 >