【问题标题】:How to iterate through a dictionary of tuples?如何遍历元组字典?
【发布时间】:2018-01-16 08:02:38
【问题描述】:

我在字典seasons 中存储了以下month,day 元组:

seasons = {
    'S1': (
        ((1, 10),(5, 31))
    ),
    'S2': (
        ((9, 1),(1, 9))
    ),
    'S3': (
        ((6, 1),(9, 30))
    )
}

我想检查日期时间dt 位于哪个日期间隔,并相应地分配名称S1S2S3

我尝试这样做,但 startend 似乎是数字而不是元组。

    def getSeason(dt):
        season = None    
        for t, ranges in seasons.items():
            for start, end in ranges:
                if date(dt.year,start(0),start(1)) <= dt.date() <= date(dt.year,end(0),end(1)):
                    season = t
                    break
            if season is not None:
                break
        return season

【问题讨论】:

  • 没有年份的日期毫无意义。您还应该存储年份。
  • @StevenRumbalski,OP 只是检查给定日期是否在一个季节内(秋季、春季等)。不需要一年。如果 OP 确实包含年份,那么使用 datetime.date 将是一个好主意。
  • @StevenRumbalski:我知道如何处理日期。就我而言,我需要没有年份的(月,日)对。嗯,我知道我应该解决的任务......
  • @Dinosaurius:如果您的数据不需要年份,它可能不应该重叠。 'S3'(9, 30) 结尾。 'S2' 开始于 (9, 1)。除非在两个季节同时放置某些东西是有效的,否则您的标准是无效的。如果您依赖迭代顺序来让一个季节优先于另一个季节,那么使用 Python 字典将无济于事,因为迭代顺序不需要遵循定义顺序。
  • @Dinosaurius:您的数据另有说明。这就是问题所在。

标签: python python-2.7 datetime dictionary tuples


【解决方案1】:

主要问题是您将元组解包,从而将int 放入startend。如果您删除嵌套循环,您的代码将按预期工作:

from datetime import datetime

seasons = {
    'S1': (
        (1, 10), (5, 31),
    ),
    'S2': (
        (9, 1), (1, 9),
    ),
    'S3': (
        (6, 1), (9, 30),
    )
}


def getSeason(dt):
    for t, (start, end) in seasons.iteritems():
        if start[0] < end[0] and datetime(dt.year, start[0], start[1]) <= dt <= datetime(dt.year, end[0], end[1]):
            return t

        elif (start[0] > end[0] and
                  (datetime(dt.year, start[0], start[1]) <= dt <= datetime(dt.year + 1, end[0], end[1]) or
                   datetime(dt.year - 1, start[0], start[1]) <= dt <= datetime(dt.year, end[0], end[1]))):
            return t

        else:
            continue

    return None

【讨论】:

  • 错误:getSeason(datetime.datetime(2017, 12, 31))getSeason(datetime.datetime(2017, 1, 1)) 每个返回 None。歧义:getSeason(datetime.datetime(2017, 9, 1)) 返回 'S3',当它很可能返回 'S2'
  • @StevenRumbalski 该错误在季节的字典定义中,因为存在重叠的值,并且并未涵盖一年中的所有日子。我添加了一个更正确的 dict 以避免原始输入问题。
  • 一个季节可以跨越一年的边界是合法的。我认为不应该被定义。
  • @StevenRumbalski 您对前两个的看法是正确的,但是对于歧义无关紧要,因为它是他的季节定义中固有的(我认为这是一个错字,S2 从 10 月 1 日开始,不是 9 月 1 日)。
【解决方案2】:

尝试以下方法:

from datetime import date

seasons = {
    'S1': (
        ((1, 10),(5, 31))
    ),
    'S2': (
        ((9, 1),(1, 9))
    ),
    'S3': (
        ((6, 1),(9, 30))
    )
}

def getSeason(dt):
    for sname, duration in seasons.items():
        start, end = duration
        start_date = date(dt.year, start[0], start[1])
        end_date = date(dt.year, end[0], end[1])
        if dt < start_date:
            start_date = date(start_date.year - 1, start_date.month, start_date.day)
            end_date = date(end_date.year - 1, end_date.month, end_date.day)
        if end_date < start_date:
            end_date = date(end_date.year+1, end_date.month, end_date.day)
        if start_date <= dt <= end_date:
            return sname
    return None

if __name__ == '__main__':
    s = getSeason(date(1921, 5, 24))
    print s

【讨论】:

  • 错误:getSeason(date(1921, 12, 31))getSeason(date(1921, 1, 1)) 各自返回 None
  • 你当然是对的,我可能误解了这个问题是关于迭代,而不是关于日期算法。
【解决方案3】:

很少有问题,我看到你的代码 -

  1. 您似乎假设您有一个元组的元组,但实际上您有一个元组的元组,因为当您尝试创建一个元素的元组时,您需要在元素后面加上 , ,否则python会将其解释为用于分组的括号。示例 -

    a = ((1,2),)
    

    在简单的情况下,

    a = (1,)
    
  2. 1234563 /li>
  3. 你的逻辑没有考虑赛季开始在一年,而赛季结束在下一年的情况。

所以季节看起来像 -

seasons = {
    'S1': (
        ((1, 10),(5, 31)),
    ),
    'S2': (
        ((9, 1),(1, 9)),
    ),
    'S3': (
        ((6, 1),(9, 30)),
    )
}

对您原来的 getSeason() 函数进行小改动,以使您的案例有效 -

def getSeason(dt):
    season = None    
    for t, ranges in seasons.items():
        for start, end in ranges:
            if start[0] <= end[0] or (start[0] == end[0] and start[1] <= end[1]):
                if date(dt.year,start[0],start[1]) <= dt.date() <= date(dt.year,end[0],end[1]):
                    season = t
                    break
            else:
                if (date(dt.year,start[0],start[1]) <= dt.date() <= date(dt.year+1,end[0],end[1])) or (date(dt.year-1,start[0],start[1]) <= dt.date() <= date(dt.year,end[0],end[1])):
                    season = t
                    break
        if season is not None:
            break
    return season

上述方法可行,但您的用例并不需要元组元组,您可以更改 getSeasons() 函数中的逻辑以使用元组元组。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-17
    • 1970-01-01
    • 1970-01-01
    • 2015-07-22
    • 1970-01-01
    • 2017-01-18
    相关资源
    最近更新 更多