5 ms·
From the article: result = [x for sublist in nested_list for x in sublist if x % 3 == 0 ] I rarely nest comprehensions, but I will occa
by a3n 10y ago
From the article:
result = [x
for sublist in nested_list
for x in sublist
if x % 3 == 0
]
I rarely nest comprehensions, but I will occasionally have more than one condition in the filter at the end, or some condition in the selection at the front.
Except for the simplest comprehensions, I tend to write mine similar to above, with indents to highlight what part of the comprehension is what.
The utility of a comprehension is not so much concise notation. Instead it's that a comprehension is an expression (that has an associated value), rather than the for loop which is a statement.
Similar to the trinary operator: its advantage is not merely that it replaces an if statement visually, it's that it's a directly usable expression (that can be composed in a (preferably short) chain of trinaries).
This highlights the four things that fizzbuzz requires:
print '\n'.join([
'fizzbuzz' if x%15 == 0 else
'fizz' if x%3 == 0 else
'buzz' if x%5 == 0 else
str(x) for x in xrange(1, 101)])
Gratuitous demo filter conditions:
print '\n'.join([
'fizzbuzz' if x%15 == 0 else
'fizz' if x%3 == 0 else
'buzz' if x%5 == 0 else
str(x) for x in xrange(1, 101)
if x%2 == 0 or x%2 != 0])
If nested comprehensions make things harder to understand, I'll sometimes move an inner comprehension out:
subrange = {x for x in range(1, 101)}
print '\n'.join([
'fizzbuzz' if x%15 == 0 else
'fizz' if x%3 == 0 else
'buzz' if x%5 == 0 else
str(x) for x in subrange
if x%2 == 0 or x%2 != 0])
EDIT: OCD forces me to rewrite:
subrange = {x for x in range(1, 101)}
print '\n'.join([
'fizzbuzz' if x%15 == 0 else
'fizz' if x%3 == 0 else
'buzz' if x%5 == 0 else
str(x)
for x in subrange
if x%2 == 0 or x%2 != 0])
FURTHER EDIT: argh!
subrange = (x for x in range(1, 101))
Original was a set comprehension. That it worked "in order" was a happy accident. Further edit is a generator.
- gspetr 10y agoFYI: if you use list comprehension within a function or method that immediately consumes the resulting list, you can usually omit it altogether: subrange = {x for x in range(1, 101)} print '\n'.join( 'fizzbuzz' if x % 15 == 0 else 'fizz' if x % 3 == 0 else 'buzz' if x % 5 == 0 else str(x) for x in subrange if x % 2 == 0 or x % 2 != 0) Notice how the '[' and ']' are missing in the code above, yet it is still both correct python and correct fizzbuzz solution and runs faster because the code does less work.
- a3n 10y agoHuh. Never seen that. But without the [] it appears to produce a generator expression (which is immediately consumed) rather than a list (which is immediately consumed). In [9]: print ' '.join(str(x) for x in range(3)) 0 1 2 In [10]: type(str(x) for x in range(3)) Out[10]: generator In [11]: type([str(x) for x in range(3)]) Out[11]: list Same effect between the two, but different and interesting things. Thanks. EDIT: Also: In [3]: %timeit ' '.join(str(x) for x in range(3)) 100000 loops, best of 3: 3.11 µs per loop In [4]: %timeit ' '.join([str(x) for x in range(3)]) 1000000 loops, best of 3: 1.47 µs per loop The list version, with the [], is about twice as fast as the generator version (without the brackets). I suspect because the generator version has to "go back to the well" for each value, but I don't really know. And this is one small test case, maybe it's different for larger sequences. Testing is everything. :)
- gspetr 10y agoI'll refer you to the original source where I picked up this trick: http://chimera.labs.oreilly.com/books/1230000000393/ch01.html#generatorargs http://chimera.labs.oreilly.com/books/1230000000393/ch01.htm... "Transforming and Reducing Data at the Same Time" I highly recommend David Beazley's excellent book, it made me a much better Python developer, helping me produce both idiomatic and efficient solutions over the last year. That book is programming poetry.
- a3n 10y agoThanks for that. Looks good so far.