7 Replies - 1194 Views - Last Post: 17 May 2012 - 09:20 PM Rate Topic: -----

#1 growthndevlpmnt  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 8
  • Joined: 14-May 12

For-loop does not iterate as expected

Posted 17 May 2012 - 07:37 AM

I have tried to write a calendar. But the for loop will only print out the days for the first month. if i try to print the days after the loop it will work. Does anyone know what is going on?


cal_year = input('Enter a year (YYYY): ')

def not_common(year):
    if (year % 4 == 0):
        if (year % 100 == 0):
            if (year % 400 == 0):
                return 1
            else:
                return 0
        else:
            return 1
    else:
        return 0

leap = not_common(cal_year)

if leap == 0:
    print 'This is not a leap year'

elif leap == 1:
    print 'This is a leap year'

else:
    print 'unexpected calculation error'

y1900=1


day = ((cal_year-1900)*365)%7

month = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
calendar = [range(1,32), range(1,29), range(1,32), range(1,31), range(1,32), range(1,31),\
         range(1,32),range(1,32),range(1,31),range(1,32),range(1,31),range(1,32)]

if (leap == 1):
    calendar[1] = range(1,30)

week = ['su','mo','tu','we','th','fr','sa']
r = 0
for i in range(0,12):
    print month[i]
    print ' '.join(str(y) for y in week)
    for j in range (1, (len(calendar[i])/7)+2):
        #cal =' '.join(str(x).zfill(2) for x in calendar[i][r*7:7*(r+1)])
            print ' '.join(str(x).zfill(2) for x in calendar[i][r*7:7*(r+1)])
            r += 1   
    print

print calendar[1]
print calendar[11]




The trouble line is believed to be:
' '.join(str(x).zfill(2) for x in calendar[i][r*7:7*(r+1)])

Is there another way to write so that it gives expected behavior?

Is This A Good Question/Topic? 0
  • +

Replies To: For-loop does not iterate as expected

#2 atraub  Icon User is offline

  • Pythoneer
  • member icon

Reputation: 759
  • View blog
  • Posts: 2,010
  • Joined: 23-December 08

Re: For-loop does not iterate as expected

Posted 17 May 2012 - 08:25 AM

The style here is a bit strange, and the code won't actually print the date on the correct days of the week, but I did find the syntax issue causing the weird behavior.

this line r = 0 needs to be the first thing in your loop. thus, your code will look like this:

week = ['su','mo','tu','we','th','fr','sa']

for i in range(0,12):
    r = 0
    print month[i]
    print ' '.join(str(y) for y in week)
    for j in range (1, (len(calendar[i])/7)+2):
        #cal =' '.join(str(x).zfill(2) for x in calendar[i][r*7:7*(r+1)])
            print ' '.join(str(x).zfill(2) for x in calendar[i][r*7:7*(r+1)])
            r += 1   
    print



EDIT:
By the way, if you want to discuss ways that this algorithm could be improved or simplified, just let us know.

EDIT 2:
Ok, I couldn't resist just a tiny bit of tweaking. Here's a function that will return True if a year is a leap year and False if it is not. I tested it againstlist of leap years from 1600 to 2200, it works perfectly according to wikipedia :)
def isLeapYear(year):
    return year %4 == 0 and (year % 100 != 0 or year % 400 == 0)

This post has been edited by atraub: 17 May 2012 - 08:44 AM

Was This Post Helpful? 1
  • +
  • -

#3 baavgai  Icon User is offline

  • Dreaming Coder
  • member icon

Reputation: 5801
  • View blog
  • Posts: 12,636
  • Joined: 16-October 07

Re: For-loop does not iterate as expected

Posted 17 May 2012 - 08:43 AM

Right, first I had to compulsively rewrite this.

I also put in some prints to try to see what was going on:
def printCal(year):
	# three nested loops?  huh?
	if (year % 4 != 0) and (year % 100 == 0) and (year % 400 == 0):
		print 'This is a leap year'
		leap = 1
	else:
		print 'This is not a leap year'
		leap = 0

	# y1900=1 # you don't use this
		
	# you go through the effort to figure this out and don't use it???
	day = ((year-1900)*365)%7

	# parallel arrays bad
	months = (('Jan', 31), ('Feb', 28 + leap), ('Mar', 31), 
		('Apr', 30), ('May', 31), ('Jun', 30),
		('Jul', 31), ('Aug', 31), ('Sep', 30), 
		('Oct', 31), ('Nov', 30), ('Dec', 31))

	week = ['su','mo','tu','we','th','fr','sa']
	r = 0
	for name, days in months:
		print name
		print ' '.join(str(y) for y in week)
		for j in range (1, days/7+2):
			rng = range(1, days+1)
			rng2 = rng[r*7:7*(r+1)]
			print rng2 # wtf is this then?
	        print ' '.join(str(x).zfill(2) for x in rng2)
	        r += 1   
		print

printCal(2012)



Results:
This is not a leap year
Jan
su mo tu we th fr sa
[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7]
01 02 03 04 05 06 07

Feb
su mo tu we th fr sa
[8, 9, 10, 11, 12, 13, 14]
[8, 9, 10, 11, 12, 13, 14]
[8, 9, 10, 11, 12, 13, 14]
[8, 9, 10, 11, 12, 13, 14]
[8, 9, 10, 11, 12, 13, 14]
08 09 10 11 12 13 14

Mar
su mo tu we th fr sa
[15, 16, 17, 18, 19, 20, 21]
[15, 16, 17, 18, 19, 20, 21]
[15, 16, 17, 18, 19, 20, 21]
[15, 16, 17, 18, 19, 20, 21]
[15, 16, 17, 18, 19, 20, 21]
15 16 17 18 19 20 21

Apr
su mo tu we th fr sa
[22, 23, 24, 25, 26, 27, 28]
[22, 23, 24, 25, 26, 27, 28]
[22, 23, 24, 25, 26, 27, 28]
[22, 23, 24, 25, 26, 27, 28]
[22, 23, 24, 25, 26, 27, 28]
22 23 24 25 26 27 28

May
su mo tu we th fr sa
[29, 30, 31]
[29, 30, 31]
[29, 30, 31]
[29, 30, 31]
[29, 30, 31]
29 30 31

Jun
su mo tu we th fr sa
[]
[]
[]
[]
[]

....



I'm thinking you cobbled this together from crap you found on the net.

Get rid of the weird cryptic join and just use a loop or two. Pad over to the first day, start looping, add a return after you hit Saturday.
Was This Post Helpful? 0
  • +
  • -

#4 atraub  Icon User is offline

  • Pythoneer
  • member icon

Reputation: 759
  • View blog
  • Posts: 2,010
  • Joined: 23-December 08

Re: For-loop does not iterate as expected

Posted 17 May 2012 - 09:05 AM

Your leapYear condition has a problem :-P

it's impossible for a value to have the following properties:
number % 4 != 0
but
number % 100 == 0

Quote

I'm thinking you cobbled this together from crap you found on the net.

I'm inclined to agree, but you gotta give the guy credit. I've seen a lot of posts from him lately about writing programs just for more experience... although writing them from scratch would definitely be a better learning exercise.

This post has been edited by atraub: 17 May 2012 - 09:13 AM

Was This Post Helpful? 1
  • +
  • -

#5 baavgai  Icon User is offline

  • Dreaming Coder
  • member icon

Reputation: 5801
  • View blog
  • Posts: 12,636
  • Joined: 16-October 07

Re: For-loop does not iterate as expected

Posted 17 May 2012 - 09:40 AM

Oops, you are correct. I'll go with yours, then.
Was This Post Helpful? 0
  • +
  • -

#6 growthndevlpmnt  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 8
  • Joined: 14-May 12

Re: For-loop does not iterate as expected

Posted 17 May 2012 - 05:15 PM

You got me. I try to do things on my own and if i can't figure it out the i try to see if someone on the net has had a similar problem.

One thing that has elicited my interest is the use use of list comprehensions and 'pythonic' code. So if have tried to implement those here. I guess I did not do it quite right. If you have some recommended reading on those topics, please share.

As far as this code. I just need to correctly offset the days in the calendar and find the right algorithm of counting leap days since 1900. This is the algorithm i tried to use:

cal_year = input('Enter a year (YYYY): ')

def is_leap(year):
    return year %4 == 0 and (year % 100 != 0 or year % 400 == 0)

if not is_leap(cal_year):
    print '\nThis is not a leap year\n'

elif is_leap(cal_year):
    print '\nThis is a leap year\n'

else:
    print '\nunexpected calculation error\n'

y1900=1


first_day = (abs(cal_year-1900)*365+abs(cal_year-1900)/4)%7
if (((cal_year-1900)%4)>0) or (cal_year == 1900):
    first_day += 1
    first_day = first_day % 7
# 


month = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
calendar = [range(1,32), range(1,29), range(1,32), range(1,31), range(1,32), range(1,31),\
         range(1,32),range(1,32),range(1,31),range(1,32),range(1,31),range(1,32)]

if is_leap(cal_year):

    calendar[1] = range(1,30)

week = ['su','mo','tu','we','th','fr','sa']

for i in range(0,12):
    r=0
    print month[i]
    print ' '.join(str(y) for y in week)
    calendar[i] = ['  ']*first_day + calendar[i]
    for j in range (1, (len(calendar[i])/7)+2):
        #cal =' '.join(str(x).zfill(2) for x in calendar[i][r*7:7*(r+1)])
            print ' '.join(str(x).zfill(2) for x in calendar[i][(j-1)*7:7*j])
            r=j
    first_day = len(calendar[i][(r-1)*7:7*r])

    print





This is my final code. Is there a way to clean it up? Do you have any suggestions?
Thanks for any input.
Was This Post Helpful? 0
  • +
  • -

#7 atraub  Icon User is offline

  • Pythoneer
  • member icon

Reputation: 759
  • View blog
  • Posts: 2,010
  • Joined: 23-December 08

Re: For-loop does not iterate as expected

Posted 17 May 2012 - 09:12 PM

Pythonic code does not mean code that uses fancy list comprehensions and awkward one-liners. Pythonic code is code that is easy to read and self documenting.

Tim Peters says it well:
>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!



Now that I've said that, you should know there is absolutely nothing pythonic about the following code:
    print ' '.join(str(y) for y in week)
    calendar[i] = ['  ']*first_day + calendar[i]
    for j in range (1, (len(calendar[i])/7)+2):
            print ' '.join(str(x).zfill(2) for x in calendar[i][(j-1)*7:7*j])
            r=j
    first_day = len(calendar[i][(r-1)*7:7*r])



It's really hard to read, it should be simple and flowing. I say ditch all that code and start from the beginning, if you run into trouble, we'll help you.
Was This Post Helpful? 0
  • +
  • -

#8 atraub  Icon User is offline

  • Pythoneer
  • member icon

Reputation: 759
  • View blog
  • Posts: 2,010
  • Joined: 23-December 08

Re: For-loop does not iterate as expected

Posted 17 May 2012 - 09:20 PM

Here, I wrote you a new one, it doesn't account for offset (ie, what day should the month start on?) but it does the printing a bit more eloquently.

def isLeapYear(year):
    return year %4 == 0 and (year % 100 != 0 or year % 400 == 0)

def getCalendar(name,dayCount):
    week = ('su','mo','tu','we','th','fr','sa',)
    cal = name + "\n"
    cal+= ' '.join(week) + "\n"

    for day in range(1,dayCount):
        cal+=str(day).zfill(2) + ' '
        if day % 7 == 0:
            cal+="\n"
    return cal
    

def main(year):
    leap = isLeapYear(year)
    if leap:
        print('This is a leap year')
    else:
        print ('This is not a leap year')
            
    months =(
         ('Jan', 31,), ('Feb', 28  +  int(leap),), #True == 1 False == 0
         ('Mar', 31,), ('Apr', 30,), ('May', 31,),
         ('Jun', 30,), ('Jul', 31,), ('Aug', 31,),
         ('Sep', 30,), ('Oct', 31,), ('Nov', 30,),
         ('Dec', 31,),
    )

    for month in months:
        #*month unpacks an iterable, so month[0] is the first param, month[1] is the second
        print(getCalendar(*month)+"\n") 

if __name__ == "__main__":
    main(2012)



Feel free to ask questions :)

This post has been edited by atraub: 17 May 2012 - 09:30 PM

Was This Post Helpful? 0
  • +
  • -

Page 1 of 1