Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

advanced listcomprehenions?

9 views
Skip to first unread message

cirfu

unread,
Jun 18, 2008, 5:42:00 PM6/18/08
to
I am wondering if it is possible to write advanced listcomprehensions.

For example:
"""Write a program that prints the numbers from 1 to 100. But for
multiples of three print "Fizz" instead of the number and for the
multiples of five print "Buzz". For numbers which are multiples of
both three and five print "FizzBuzz"."""
Obv it doesnt have to be a list according tot hat definition but
suppose i want to generate that list.

>>> [["Fizzbuzz",x] for x in xrange(1,101) if x%3 == 0 and x%5 == 0]
[['Fizzbuzz', 15], ['Fizzbuzz', 30], ['Fizzbuzz', 45], ['Fizzbuzz',
60], ['Fizzbuzz', 75], ['Fizzbuzz', 90]]

is not what i want. the following does the trick but is ldo not a
listcomprehension:

for i in xrange(1,101):
s = ""
if i%3 == 0:
s += "Fizz"
if i%5 == 0:
s += "Buzz"
if s:
print "%d : %s" % (i,s)
else:
print i

or to generate a lisrt but not by listcomprehsnion:
map(lambda x: (not x%3 and not x%5 and "FizzBuzz") or (not x%3 and
"Fizz")
or (not x%5 and "Buzz") or x, xrange(1,101))

Gabriel Genellina

unread,
Jun 18, 2008, 6:55:16 PM6/18/08
to pytho...@python.org
En Wed, 18 Jun 2008 18:42:00 -0300, cirfu <circul...@yahoo.se> escribió:

> I am wondering if it is possible to write advanced listcomprehensions.
>
> For example:
> """Write a program that prints the numbers from 1 to 100. But for
> multiples of three print "Fizz" instead of the number and for the
> multiples of five print "Buzz". For numbers which are multiples of
> both three and five print "FizzBuzz"."""
> Obv it doesnt have to be a list according tot hat definition but
> suppose i want to generate that list.

Go to http://groups.google.com/group/comp.lang.python and search for "fizz
buzz"...

> or to generate a lisrt but not by listcomprehsnion:
> map(lambda x: (not x%3 and not x%5 and "FizzBuzz") or (not x%3 and
> "Fizz")
> or (not x%5 and "Buzz") or x, xrange(1,101))

You can translate that into a list comprehension - in general, map(f,
items) is the same as [f(x) for x in items]. We have then:

[(not x%3 and not x%5 and "FizzBuzz") or (not x%3 and "Fizz") or (not x%5
and "Buzz") or x for x in xrange(1,101)]

Quite unreadable IMHO. Just to add another variant to the zillion ones
already posted:

def fb(x):
mult3 = x%3 == 0
mult5 = x%5 == 0
if mult3 and mult5: return "FizzBuzz"
elif mult3: return "Fizz"
elif mult5: return "Buzz"
return str(x)

[fb(x) for x in range(1,101)]

--
Gabriel Genellina

MRAB

unread,
Jun 18, 2008, 7:29:50 PM6/18/08
to

[("FizzBuzz" if n % 15 == 0 else "Fizz" if n % 3 == 0 else "Buzz" if n
% 5 == 0 else str(n)) for n in range(1, 101)]

Dan Bishop

unread,
Jun 18, 2008, 8:01:17 PM6/18/08
to

[(('Fizz' if num % 3 == 0 else '') + ('Buzz' if num % 5 == 0 else ''))
or str(num) for num in xrange(1, 101)]

Mark Wooding

unread,
Jun 19, 2008, 7:57:47 AM6/19/08
to
Gabriel Genellina <gags...@yahoo.com.ar> wrote:

> [(not x%3 and not x%5 and "FizzBuzz") or (not x%3 and "Fizz") or (not x%5
> and "Buzz") or x for x in xrange(1,101)]

Rather unpleasant. Note that a number is zero mod both 3 and 5 if and
only if it's zero mod 15. But we can do better.

A simple application of Fermat's Little Theorem (to distinguish units
mod 3 and 5 from non-units) gives us this:

[['FizzBuzz', 'Buzz', 'Fizz', False][pow(i, 2, 3) + 2*pow(i, 4, 5)] or
str(i) for i in xrange(1, 101)]

This is still inelegant, though. We can glue the results mod 3 and 5
together using the Chinese Remainder Theorem and working mod 15
instead. For example,

[['Fizz', 'FizzBuzz', False, None, 'Buzz'][(pow(i, 4, 15) + 1)%7] or
str(i) for i in xrange(1, 101)]

(A less mathematical approach would just use i%15 to index a table. But
that's not interesting. ;-) )

-- [mdw]

Duncan Booth

unread,
Jun 19, 2008, 8:54:31 AM6/19/08
to
Mark Wooding <m...@distorted.org.uk> wrote:

> This is still inelegant, though. We can glue the results mod 3 and 5
> together using the Chinese Remainder Theorem and working mod 15
> instead. For example,
>
> [['Fizz', 'FizzBuzz', False, None, 'Buzz'][(pow(i, 4, 15) + 1)%7] or
> str(i) for i in xrange(1, 101)]
>
> (A less mathematical approach would just use i%15 to index a table. But
> that's not interesting. ;-) )
>

Ooh. Doesn't having 5 elements make you shudder? (Even though you did
change one to avoid a repeated value.) You have 4 options for output, so
for elegance that list should also have 4 elements:

[[str(i), 'FizzBuzz', 'Fizz', 'Buzz'][25/(pow(i, 4, 15) + 1)%4] for i in
xrange(1, 101)]

I feel it is even more elegant with the lookup table in its natural order:

[['Fizz', 'Buzz', 'FizzBuzz', str(i)][62/(pow(i, 4, 15) + 1)%4] for i in
xrange(1, 101)]

:)

--
Duncan Booth http://kupuguy.blogspot.com

Mark Wooding

unread,
Jun 19, 2008, 11:39:05 AM6/19/08
to
Duncan Booth <duncan...@invalid.invalid> wrote:

> [['Fizz', 'Buzz', 'FizzBuzz', str(i)][62/(pow(i, 4, 15) + 1)%4] for i in
> xrange(1, 101)]

Cute! ;-)

-- [mdw]

Terry Reedy

unread,
Jun 19, 2008, 9:29:53 PM6/19/08
to pytho...@python.org

Duncan Booth wrote:
> Mark Wooding <m...@distorted.org.uk> wrote:
>
>> This is still inelegant, though. We can glue the results mod 3 and 5
>> together using the Chinese Remainder Theorem and working mod 15
>> instead. For example,
>>
>> [['Fizz', 'FizzBuzz', False, None, 'Buzz'][(pow(i, 4, 15) + 1)%7] or
>> str(i) for i in xrange(1, 101)]

The lookup table is a constant. If made a tuple, it will be compiled as
a constant (as least in 2.6, maybe 2.5). In any case, it could (and to
me should) be lifted out of the string comp.

>>
>> (A less mathematical approach would just use i%15 to index a table. But
>> that's not interesting. ;-) )
>>
>
> Ooh. Doesn't having 5 elements make you shudder? (Even though you did
> change one to avoid a repeated value.) You have 4 options for output, so
> for elegance that list should also have 4 elements:
>
> [[str(i), 'FizzBuzz', 'Fizz', 'Buzz'][25/(pow(i, 4, 15) + 1)%4] for i in
> xrange(1, 101)]
>
> I feel it is even more elegant with the lookup table in its natural order:
>
> [['Fizz', 'Buzz', 'FizzBuzz', str(i)][62/(pow(i, 4, 15) + 1)%4] for i in
> xrange(1, 101)]

These make the lookup table variable, so it has to be recalculated for
each i.

tjr

Duncan Booth

unread,
Jun 20, 2008, 3:31:19 AM6/20/08
to
Terry Reedy <tjr...@udel.edu> wrote:

>> [['Fizz', 'Buzz', 'FizzBuzz', str(i)][62/(pow(i, 4, 15) + 1)%4] for i
>> in xrange(1, 101)]
>
> These make the lookup table variable, so it has to be recalculated for
> each i.
>

So what? Mark Wooding was posting about mathematical elegance and came up
with that really neat pow() call. If runtime came into it then one of the
previous solutions or (as Mark already said) a straightforward sometable[i%
15] is going beat something like this hands-down.

This is coding for fun not profit.

Ivan Illarionov

unread,
Jun 20, 2008, 4:27:06 AM6/20/08
to
On 20 июн, 11:31, Duncan Booth <duncan.bo...@invalid.invalid> wrote:

I can't resist...
[[i,"Fizz","Buzz","FizzBuzz"][(not i%3)+(not i%5)*2] for i in range(1,
101)]

Ivan

Mark Wooding

unread,
Jun 21, 2008, 10:55:40 AM6/21/08
to
Terry Reedy <tjr...@udel.edu> wrote:

> The lookup table is a constant. If made a tuple, it will be compiled as
> a constant (as least in 2.6, maybe 2.5).

Force of habit. I tend to work on lists by indexing and/or iterating,
and on tuples by destructuring, and choose types based on the kinds of
things I'll be doing. But I did intentionally ensure that the tables
were constant so that readers could apply the obvious optimization if
they wanted. (Also, unnecessarily computing str(i) seemed bad.)

> In any case, it could (and to me should) be lifted out of the string
> comp.

For performance, yes. But doing a modexp is going to kill performance
anyway, so I decided to save screen lines. After all, applying even
fairly basic number theory to a problem like this isn't really what one
might call a readable solution. ;-)

-- [mdw]

0 new messages