How to iterate over a dictionary of tuples?

I have the following tuples month,day

stored in a dictionary seasons

:

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

      

I want to check what date-time range is in dt

and assign a name S1

, S2

or S3

, respectively.

I tried to do it this way, but start

also end

appear to be numbers instead of tuples.

    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

      

+3


source to share


3 answers


Several questions I see with your code -

  • You seem to be assuming that you have a tuple of tuples of tuples, but in reality you have a tuple is dumb because when you try to make a tuple of a single element, you need to follow the element with ,

    , otherwise python will interpret it as parentheses. used for grouping. Example -

    a = ((1,2),)
    
          

    In a simple case

    a = (1,)
    
          

  • Second, when accessing the value of a tuple, you should use start[0]

    , not start(0)

    as the latter is trying to call it as a function, with a parameter 0

    .

  • Your logic is not considering the case where the start of the season is one year and the end of the season is next year.

So the seasons look like

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

      



Small change in your original function getSeason()

to make your case work -

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

      

The above will work, but you don't need a tuple of tuples for your use case, you can change the logic in your function getSeasons()

to use a tuple of a tuple.

+2


source


The main problem is that you are unpacking the tuple, getting int

in start

and out end

. if you remove the nested loop, your code works as you expect:



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

      

-1


source


Try the following:

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

      

-1


source







All Articles