Reputation: 113
Can the following be coded more compactly using list comprehension?
labels=[]
for i in range(10):
labels=labels+[i]+9*['']
labels=labels+[10]
Upvotes: 2
Views: 151
Reputation: 2063
This reads to me like "create an array 101 elements in length, where each item is an empty string if its index is a non-integer multiple of 10, otherwise it's the index-divided-by-10". As a list comprehension:
>>> ['' if i % 10 else i / 10 for i in xrange(101)]
[0, '', '', '', '', '', '', '', '', '', 1, '', '', '', '', '', '', '', '', '', 2, '', '', '', '', '', '', '', '', '', 3, '', '', '', '', '', '', '', '', '', 4, '', '', '', '', '', '', '', '', '', 5, '', '', '', '', '', '', '', '', '', 6, '', '', '', '', '', '', '', '', '', 7, '', '', '', '', '', '', '', '', '', 8, '', '', '', '', '', '', '', '', '', 9, '', '', '', '', '', '', '', '', '', 10]
That said, if the list comprehension isn't an absolute requirement, I find something like this quite a bit easier to grok:
>>> y = []
>>> for i in xrange(10):
... y.append(i)
... y.extend([''] * 9)
...
>>> y.append(10)
(which is almost identical to your original approach)
Upvotes: 0
Reputation: 20
Here is the code you are looking for
labels=[j for i in range(10) for j in [i]+9*['']]+[10]
Upvotes: 0
Reputation: 96984
It is convoluted, but if you want a list comprehension, this is one way to do it:
[i for s in [[x] + 9*[''] if x < 10 else [x] for x in range(11)] for i in s]
Demo:
>>> labels = [i for s in [[x] + 9*[''] if x < 10 else [x] for x in range(11)] for i in s]
>>> labels
[0, '', '', '', '', '', '', '', '', '', 1, '', '', '', '', '', '', '', '', '', 2, '', '', '', '', '', '', '', '', '', 3, '', '', '', '', '', '', '', '', '', 4, '', '', '', '', '', '', '', '', '', 5, '', '', '', '', '', '', '', '', '', 6, '', '', '', '', '', '', '', '', '', 7, '', '', '', '', '', '', '', '', '', 8, '', '', '', '', '', '', '', '', '', 9, '', '', '', '', '', '', '', '', '', 10]
By way of comparison:
>>> labels=[]
>>> for i in range(10):
... labels=labels+[i]+9*['']
...
>>> labels=labels+[10]
>>> labels
[0, '', '', '', '', '', '', '', '', '', 1, '', '', '', '', '', '', '', '', '', 2, '', '', '', '', '', '', '', '', '', 3, '', '', '', '', '', '', '', '', '', 4, '', '', '', '', '', '', '', '', '', 5, '', '', '', '', '', '', '', '', '', 6, '', '', '', '', '', '', '', '', '', 7, '', '', '', '', '', '', '', '', '', 8, '', '', '', '', '', '', '', '', '', 9, '', '', '', '', '', '', '', '', '', 10]
Upvotes: 1
Reputation: 159875
Here's one way to break this down.
If you look at the main body of your loop, you can restructure it as generating a sublist for each number, and then combining the sublists together.
sublists = []
for i in range(10):
sublists.append([i] + 9 * [''])
labels = []
for sublist in sublists:
labels = labels + sublist
labels = labels + [10]
The first part of this takes a list of numbers, calls the same function on each of them, and produces a list of results. This operation is map (and indeed has this name in many languages). The second part takes a list of lists and flattens them into one big list; many languages have a "concat" or "flatten" operation, but in Python it can be a little clunky.
from itertools import chain
sublists = map(range(10), lambda i: [i] + 9 * [''])
labels = list(chain.from_iterable(sublists))
labels = labels + [10]
The map()
call in particular easily transforms into a list comprehension (or a generator comprehension)
from itertools import chain
sublists = [[i] + 9 * [''] for i in range(10)]
labels = list(chain.from_iterable(sublists))
labels = labels + [10]
and so if you want to turn this into a one-liner you can have
from itertools import chain
labels = list(chain.from_iterable([i] + 9 * [''] for i in range(10))) + [10]
For something completely different, you could potentially use a generator function to make it clearer what you're doing. Really, for each item in the input, you're emitting the item, and if it's not the last item, emitting nine lists containing empty strings. You can then take the sequence produced by the generator function and convert it to a list.
def emit_with_blanks(iter):
l = list(iter)
for i, n in enumerate(l):
yield [i]
if i == len(l) - 1:
break
for _ in range(9):
yield ['']
labels = list(emit_with_blanks(range(10))
This is definitely longer and slower (in a way that shouldn't matter in practice) but it could be easier to reason about what it's doing than the one-liner, especially if you come back to it six months later and are trying to remember what exactly the code does.
Upvotes: 2