[ACCEPTED]-List comprehension and len() vs. simple for loop-list-comprehension

Accepted answer
Score: 17

In your second example a generator expression would be better 1 than list-comp if your list is large.

sum(1 for word in words if len(word) >= 2 and word[0] == word[-1])
Score: 4

The first one would definitely be the preferred 20 solution in Python.

Don't forget your Zen 19 of Python:

The Zen of Python, by Tim Peters

Beautiful is better than ugly.

Explicit 18 is better than implicit.

Simple is better 17 than complex.

Complex is better than complicated.

Flat 16 is better than nested.

Sparse is better 15 than dense.

Readability counts.

Special cases aren't special 14 enough to break the rules.

Although practicality 13 beats purity.

Errors should never pass silently.

Unless 12 explicitly silenced.

In the face of ambiguity, refuse 11 the temptation to guess.

There should 10 be one-- and preferably only one --obvious 9 way to do it.

Although that way may not 8 be obvious at first unless you're Dutch.

Now 7 is better than never.

Although never is 6 often better than right now.

If the implementation 5 is hard to explain, it's a bad idea.

If 4 the implementation is easy to explain, it 3 may be a good idea.

Namespaces are one honking 2 great idea -- let's do more of those!

Other 1 than that your solutions are good.

Score: 2

I personally find the explicit loop more 10 readable, but it's much a matter of taste 9 (some prefer shorter code generally, especially 8 when they have to write it).

Either version 7 can be further shortened/improved:

result = 0
for word in words:
    result += int(len(word) >= 2 and word[0] == word[-1])
return result

The int() conversions 6 is strictly speaking unnecessary, since 5 True is a kind of 1, but it may be better 4 for readability. The same approach can apply 3 to the comprehension:

return sum(len(word) >= 2 and word[0] == word[-1] for word in words)

If you want to use 2 len(), I'd point the reader to the fact 1 that the values don't really matter:

len(1 for word in words if len(word) >= 2 and word[0] == word[-1])
Score: 1

Both are pretty good.

There are small differences:

List 3 comprehension returns another list which 2 you are passing to len. The first solution 1 avoids creation of another list.

Score: 1

Some other variants you might want to consider:

First, you 15 can break the filter condition into a function. This 14 condition is fine either way, but if it 13 becomes any more complex I'd definitely 12 do this:

def check(word):
    return len(word) >= 2 and word[0] == word[-1]
sum(1 for word in words if check(word))

Next, if generating a list (as in 11 the original list comprehension) is acceptable, then 10 you can do this:

len(filter(check, words))

There's itertools.ifilter, but 9 if you use that you need to use the sum expression 8 again, so it doesn't end up any clearer.

The 7 sum trick comes up so often that I'm surprised 6 there isn't a standard library call to count 5 the number of items in an iterator (if there 4 is, I havn't found it). Alternatively, it'd 3 make sense if len would consume and count the 2 number of entries in an iterator if it has 1 no __len__, but it doesn't.

More Related questions