Pat a écrit :
I have written chunks of Python code that look this:
new_array = []
for a in array:
if not len( a ):
continue
new_array.append( a )
# à la lisp
new_array = filter(None, array)
# à la haskell
new_array = [a for a in array if a]
NB : all builtin empty builtin sequence type have a false boolen value,
so 'not len(a)' and 'not a' are usually practicaly equivalent.
<ot>
While we're at it : I assume you mean 'list', not 'array'. That's at
least how the builtin type is named...
</ot>
and...
string = ""
for r in results:
if not r.startswith( '#' ):
string =+ r
# à la lisp
string = "".join(filter(lambda s: not s.startwith('#'), results)
# à la haskell
string = "".join(r for r in results if not s.startswith('#'))
It seems that a list comprehension could clean up the code, but I seem
to have a mental block on list comprehensions. I've read up a lot on
this subject in my books and on the Internet and for whatever reason,
I'm having problems with this idiom (if that's the correct expression).
I've made a number of attempts to solve this on my own but I keep
getting errors.
Could someone please tell me how I could convert the above code to
something more elegant but readily understandable?
Basically, a list expression is written as (pseudo BNF):
'['<expression> for item in <iterable_expression> [if
<conditional_expression>] ']'
where
- <expression> is any Python expression
- <iterable_expression> is any Python expression that evals to an iterable
- the 'if <conditional_expression>' part is optional
The resulting list will be obtained by evaluating <expression> for each
item of <iterable_expression> for which <conditional_expression> is
verified.
Since the main goal of list expressions is to build, well, lists, one
usually uses an <expression> that evals to something we possibly want to
be part of the new list !-)
Now for something more practical:
First let's rewrite your first snippet to get rid of the continue statement:
new_list = []
for item in source_list:
if len(item):
new_list.append(item)
And let's rewrite the second one to replace string concatenation with
the more idiomatic (and much more flexible) list / join idiom:
new_list = []
for item in results:
if not item.startswith('#'):
new_list.append(item)
string = "".join(new_list)
You may start to see a kind of pattern here:
0. new_list = []
1. for item in sequence:
2. if condition(item):
3. new_list.append(item)
The equivalent list comprehension is:
new_list = [item for item in sequence if condition(item)]
Since you didn't apply any transformation to 'item' in your for loops,
the <expression> part is as simple as it can be : we want the item, period.
The <iterable_expression> is here again quite simple : it's your source
sequence. Ditto for the the <conditional_expression>.
IOW, your for-loop pattern is really:
new_list = []
for item in <iterable_expression>:
if <conditional_expression>:
new_list.append(<expression>)
Once you've identified the different parts, translating this for-loop to
a list comprehension is mostly a matter of reording.
Finally, if someone could point me to a good tutorial or explain list
compressions I would be forever in your debt.
http://en.wikipedia.org/wiki/List_comprehension
http://en.wikipedia.org/wiki/Set-builder_notation
HTH
--
http://mail.python.org/mailman/listinfo/python-list