advanced listcomprehenions?

C

cirfu

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))
 
G

Gabriel Genellina

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)]
 
M

MRAB

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))

[("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)]
 
D

Dan Bishop

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))

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

Mark Wooding

Gabriel Genellina said:
[(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]
 
T

Terry Reedy

Duncan said:
Mark Wooding said:
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
 
I

Ivan Illarionov

Terry Reedy said:
[['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.

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

Ivan
 
M

Mark Wooding

Terry Reedy said:
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]
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top