Re: [Tutor] Poor style to use list as "array"?

2009-07-06 Thread Angus Rodgers
On Mon, 6 Jul 2009 01:51:22 +0100, Rich Lovely wrote:

[I wrote:]
>>                if name in plural:
>>                    name = plural[name]
>>                else:
>>                    name += 's'
>This could be written more cleanly (although arguably not as readably) as
>
>name = plural.get(name, name + "s")

Nice, and readable enough, I think.

>d.get(key, default) returns the value from d mapped to key if it
>exists, or default otherwise.
>
>You might also want to split your calculation and display code into
>two separate loops.  This might seem wasteful, but it will make your
>code easier to read and maintain, and the waste is only marginal with
>the loops you're running - there is a maximum of only 17 passes (once
>for each value of coin and note)

If I understand you correctly, this is the same idea as Bob Gailer
used in his code - in which 'buff' becomes a list, instead of (as
in my code) a string, formatted for printing.  It certainly seems 
to simplify the whole thing enormously:

   (retention: 1 day)
(Ignore the boilerplate!)

Thanks to all of you.  I haven't adopted the suggestion of using
classes, which I think I'll leave for when I'm reading the later
chapters of the book (although I do get the gist of the idea).
-- 
Angus Rodgers
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Poor style to use list as "array"? CORRECTION

2009-07-06 Thread bob gailer

class Coin:

def __init__(self, name, value, plural=None):
  self.name = name
  self.value = value
  if plural:
self.plural = plural
  else:
self.plural = self.name + 's'
  self.count = 0

def display(self):
  if self.count == 0:
return None
  if self.count == 1:
return "%d %s" % (self.count, name)
  else:
return "%d %s" % (self.count, self.plural)

 next line unindented ###

coins = Coin('dollar', 100), Coin('quarter', 25), Coin('dime', 10), 
Coin('nickel', 5), Coin('penny', 1, 'pennies')

amnt = 99
buff = []
for coin in coins:
(coin.count, amnt) = divmod(amnt, coin.value)
d = coin.display()
if d:
  buff.append(d)
if len(buff) < 2:
print buff
else:
print ', '.join(buff[:-1]) + " and " + buff[-1]

--
Bob Gailer
Chapel Hill NC
919-636-4239
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Poor style to use list as "array"?

2009-07-05 Thread bob gailer

Angus Rodgers wrote:

The problem this time is, given an amount of US currency in cents
(and less than a dollar), to print out a description of the coins
needed to represent it, using the smallest number of coins.  E.g.:

How many cents this time? 59
2 quarters, 1 nickel and 4 pennies.

How many cents this time? 55
2 quarters and 1 nickel.

How many cents this time? 75
3 quarters.

My program relaxes the restriction to amounts less than a dollar,
and initialises the necessary data structures as follows:

denom = ['dollar', 'quarter', 'dime', 'nickel', 'penny']
value = [100, 25, 10, 5, 1]
LEN = 5
plural = [None] * LEN
plural[-1] = 'pennies'
count = [None] * LEN   # Kludge
  


I'm inclined to use a class. I omitted the input and loop for "simplicity".

class Coin:

 def __init__(self, name, value, plural=None):
   self.name = name
   self.value = value
   if plural:
 self.plural = plural
   else:
 self.plural = self.name + 's'
   self.count = 0

 def display(self):
   if self.count == 0:
 return None
   if self.count == 1:
 return "%d %s" % (self.count, name)
   else:
 return "%d %s" % (self.count, self.plural)
   
coins = Coin('dollar', 100), Coin('quarter', 25), Coin('dime', 10), 
Coin('nickel', 5), Coin('penny', 1, 'pennies')

amnt = 99
buff = []
for coin in coins:
 (coin.count, amnt) = divmod(amnt, coin.value)
 d = coin.display()
 if d:
   buff.append(d)
if len(buff) < 2:
 print buff
else:
 print ', '.join(buff[:-1]) + " and " + buff[-1]


I use the list 'count' as a kind of array, so that e.g. count[-1]
is the number of pennies needed, count[2] is the number of dimes
needed, and so on.  Any initial values I might store as elements
of the list are never used, hence the use of 'None'. (The use of
'None' in the list 'plural' is much more defensible, I think, as
it is used to denote the formation of a regular plural by adding
's' to the name.) Instead, the actual values are assigned in a
'for' loop, as follows:

for i in range(LEN - 1):
(count[i], amnt) = divmod(amnt, value[i])

This feels like a bit of a cheat, as if I am trying to program in
Python as if it were some other more familiar language.  Should I
have coded this differently?

The full source code is here, in case anyone wants to look at it
(but I'm not soliciting any more attention, as I've already been
given quite a lot of it, and fear being offered the comfy chair!):
   (retention: 1 day)

Could I have used dictionaries instead, with the denomination names
as keys?  Is it possible to guarantee a sequence in which the keys
of a dictionary are iterated through? (If not, I suppose I could
keep the list 'denom' as it is here, and iterate through it with
"for key in denom:", although this seems a bit redundant.)
  



--
Bob Gailer
Chapel Hill NC
919-636-4239
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Poor style to use list as "array"?

2009-07-05 Thread Rich Lovely
>                if name in plural:
>                    name = plural[name]
>                else:
>                    name += 's'
This could be written more cleanly (although arguably not as readably) as

name = plural.get(name, name + "s")

d.get(key, default) returns the value from d mapped to key if it
exists, or default otherwise.

You might also want to split your calculation and display code into
two separate loops.  This might seem wasteful, but it will make your
code easier to read and maintain, and the waste is only marginal with
the loops you're running - there is a maximum of only 17 passes (once
for each value of coin and note)

-- 
Richard "Roadie Rich" Lovely, part of the JNP|UK Famile
www.theJNP.com
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Poor style to use list as "array"?

2009-07-05 Thread Angus Rodgers
On Mon, 06 Jul 2009 01:02:10 +0100, I hastily wrote:

>Incidentally, I forgot to quote the next line:
>
>count[-1] = m

That was copied-and-pasted from an older version of the program,
with less descriptive identifiers.  'm' should be 'amnt'.

>Of course, this is much better incorporated into the loop, thus:
>
>for i in range(LEN):
>(count[i], amnt) = divmod(amnt, value[i])
>
>[...]
>
>So it looks like we should have something like:
>
>plural = {'penny':'pennies'}
>
>counts = {}
>for val in value:
>(count, amnt) = divmod(amnt, val)
>counts[val] = count

Better, of course (I still haven't run it, but it should work):

counts = {}
for val in value:
(counts[val], amnt) = divmod(amnt, val)

>I'm much happier now, thanks!

... but also rather annoyed with myself.
-- 
Angus Rodgers
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Poor style to use list as "array"?

2009-07-05 Thread Angus Rodgers
On Sun, 5 Jul 2009 18:49:32 -0400, Kent Johnson wrote:

>On Sun, Jul 5, 2009 at 2:48 PM, Angus Rodgers wrote:
>
>> for i in range(LEN - 1):
>>    (count[i], amnt) = divmod(amnt, value[i])

Incidentally, I forgot to quote the next line:

count[-1] = m

Of course, this is much better incorporated into the loop, thus:

for i in range(LEN):
(count[i], amnt) = divmod(amnt, value[i])

and this lends itself to being rewritten in terms of some other
kind of iteration (as below).

>How about this:
>counts = []
>for val in value:
>  count, amnt = divmod(amnt, val)
>  counts.append(count)

I like that very much, because it is in the nature of the problem
that the numbers in the list 'value' are all distinct, and so can
be used as keys.  However, as this remark suggests, I think I am
going to need 'count' to be a dictionary, rather than a list, and
the same goes for 'denom', and 'plural' (although this should be
keyed by the strings in 'denom', and we don't need the 'None's).

So it looks like we should have something like:

plural = {'penny':'pennies'}

counts = {}
for val in value:
(count, amnt) = divmod(amnt, val)
counts[val] = count

and, later in the program, something like this (comments stripped
for brevity, and one new comment added):

for val in value:
amnt = counts[val]
name = denom[val]
if amnt:
to_print -= 1
if printed:
if to_print:
buff += ", "
else:
buff += " and "
printed += 1
if amnt > 1:
# This should become a function
if name in plural:
name = plural[name]
else:
name += 's'
buff += "%d %s" % (amnt, name)

I haven't run this, but I'll try rewriting the program tomorrow.
It looks like there's nothing to it.

I'm much happier now, thanks!
-- 
Angus Rodgers
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Poor style to use list as "array"?

2009-07-05 Thread Alan Gauld


"Angus Rodgers"  wrote 


as keys?  Is it possible to guarantee a sequence in which the keys
of a dictionary are iterated through? 


Indirectly yes:

for key in sorted( dct ):
   print key

I would definitely tend to go with a dictionary for the 
denominations/values in this case  (Actually I'd probably 
go for a class but that's another ball game entirely!)



--
Alan Gauld
Author of the Learn to Program web site
http://www.alan-g.me.uk/

___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Poor style to use list as "array"?

2009-07-05 Thread Kent Johnson
On Sun, Jul 5, 2009 at 2:48 PM, Angus Rodgers wrote:

> for i in range(LEN - 1):
>    (count[i], amnt) = divmod(amnt, value[i])

How about this:
counts = []
for val in value:
  count, amnt = divmod(amnt, val)
  counts.append(count)

> This feels like a bit of a cheat, as if I am trying to program in
> Python as if it were some other more familiar language.  Should I
> have coded this differently?

Generally it's more straighforward to iterate over a list directly
rather than using an index.

> The full source code is here, in case anyone wants to look at it
> (but I'm not soliciting any more attention, as I've already been
> given quite a lot of it, and fear being offered the comfy chair!):

Don't worry, we have retired the comfy chair.

> Could I have used dictionaries instead, with the denomination names
> as keys?  Is it possible to guarantee a sequence in which the keys
> of a dictionary are iterated through?

In general no. Python 2.7 and 3.1 do have an ordered dictionary:
http://www.python.org/dev/peps/pep-0372/

Kent
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Poor style to use list as "array"?

2009-07-05 Thread Noufal Ibrahim

Angus Rodgers wrote:
[..]


This feels like a bit of a cheat, as if I am trying to program in
Python as if it were some other more familiar language.  Should I
have coded this differently?


I can't offer anything concrete but here are some things that occur to 
me at a glance.


0. You can try to use the collections module in 2.6 (especially the 
namedtuple object which gives you access to things through attributes as 
well as through order.
1. You have 3 lists (denom, plural and count) which you will iterate 
through in lockstep as far as I can tell. It's an option to use a list 
of 3-tuples or a list of dictionaries with three keys (denomination, 
plural and count).


Thanks.

--
~noufal
http://nibrahim.net.in/
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


[Tutor] Poor style to use list as "array"?

2009-07-05 Thread Angus Rodgers
The problem this time is, given an amount of US currency in cents
(and less than a dollar), to print out a description of the coins
needed to represent it, using the smallest number of coins.  E.g.:

How many cents this time? 59
2 quarters, 1 nickel and 4 pennies.

How many cents this time? 55
2 quarters and 1 nickel.

How many cents this time? 75
3 quarters.

My program relaxes the restriction to amounts less than a dollar,
and initialises the necessary data structures as follows:

denom = ['dollar', 'quarter', 'dime', 'nickel', 'penny']
value = [100, 25, 10, 5, 1]
LEN = 5
plural = [None] * LEN
plural[-1] = 'pennies'
count = [None] * LEN   # Kludge

I use the list 'count' as a kind of array, so that e.g. count[-1]
is the number of pennies needed, count[2] is the number of dimes
needed, and so on.  Any initial values I might store as elements
of the list are never used, hence the use of 'None'. (The use of
'None' in the list 'plural' is much more defensible, I think, as
it is used to denote the formation of a regular plural by adding
's' to the name.) Instead, the actual values are assigned in a
'for' loop, as follows:

for i in range(LEN - 1):
(count[i], amnt) = divmod(amnt, value[i])

This feels like a bit of a cheat, as if I am trying to program in
Python as if it were some other more familiar language.  Should I
have coded this differently?

The full source code is here, in case anyone wants to look at it
(but I'm not soliciting any more attention, as I've already been
given quite a lot of it, and fear being offered the comfy chair!):
   (retention: 1 day)

Could I have used dictionaries instead, with the denomination names
as keys?  Is it possible to guarantee a sequence in which the keys
of a dictionary are iterated through? (If not, I suppose I could
keep the list 'denom' as it is here, and iterate through it with
"for key in denom:", although this seems a bit redundant.)
-- 
Angus Rodgers
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor