Getting all possible combinations of list items
Alex Martelli
aleax at aleax.it
Mon Sep 17 07:27:29 EDT 2001
"Martin von Loewis" <loewis at informatik.hu-berlin.de> wrote in message
news:j4g09mdvvt.fsf at informatik.hu-berlin.de...
> "Greg Krohn" <volucris at hotmail.com> writes:
>
> > scratching my head over 'magic' code,
>
> I prefer explicit loops over map and lambdas:
So do I, but building up a large string (here, the one
in the variable called number) by +'ing small ones in
a loop is a disaster. So, I'd make a small mod here:
> def magic_algorithm(another_list, count):
> length = len(another_list)
> result = []
> for i in xrange(length**count):
> number = ''
change this line to:
number = []
> for pos in range(count):
> # prepend the next digit
> number = another_list[i % length] + number
change this line to:
number.append(another_list[i % length])
> i = i / length
> result.append(number)
change this line to:
number.reverse()
result.append(''.join(number))
> return result
The number.reverse() line may not be needed if the
SET of strings returned, rather than their order,
is what one is after, as is typically the case.
I think it would be even clearer if we avoided the
inner loop in favour of a clearer one, i.e.,
rewriting the whole thing for clarity:
def magic_algorithm(another_list, count):
length = len(another_list)
result = []
for i in xrange(length**count):
number = []
for dig in digits_in_base(i, length, count):
number.append(another_list[dig])
result.append(''.join(number))
return result
where, e.g. and still emphasizing clarity:
def digits_in_base(value, base, ndigits):
result = ndigits*[0]
i = ndigits-1
while value and i>=0:
result[i] = value%base
value /= base
i -= 1
return result
With this auxiliary function at hand we may also
rewrite magic_algorithm using list comprehension,
e.g. for the inner loop only:
def magic_algorithm(another_list, count):
length = len(another_list)
result = []
for i in xrange(length**count):
result.append(''.join([another_list[dig]
for dig in digits_in_base(i, length, count)]))
return result
or for both loops:
def magic_algorithm(another_list, count):
length = len(another_list)
return [''.join([another_list[dig]
for dig in digits_in_base(i, length, count)])
for i in xrange(length**count)]
but either or both of these might be considered as
over-application of the list comprehension form,
depending of course on one's attitude to list
comprehension form itself. Personally, I prefer
the penultimate one, because it seems to me that
the last one is hard to follow -- it's unusual to
have a list comprehension inside another list
comprehension, after all. But there's not much to
choose among them except personal taste issues:-).
Alex
More information about the Python-list
mailing list