Anagram
Alex Martelli
aleax at aleax.it
Thu Jan 24 07:00:43 EST 2002
"Joseph A Knapka" <jknapka at earthlink.net> wrote in message
news:3C4ED1A5.56CE7B60 at earthlink.net...
...
> # This one allows you to pick an anagram from anywhere
> # in the sequence. <Ana> is the index of the anagram to
> # pick from the possible anagrams of <lis>.
> def pickana(lis,ana):
> if not lis:
> return []
> idx1 = int(ana/fact(len(lis)-1))
> which1 = lis[idx1]
>
> # Still annoying. Can I "comprehend" this somehow?
> llis = lis[:]
> del llis[idx1]
Not sure what you mean. "get the idx1-th element
from list llis and remove it from the list too"
is llis.pop(idx1); is that what you mean by
"comprehend"?
> rest = pickana(llis,ana%fact(len(lis)-1))
> return [which1] + rest
Or, non-recursively...:
def pickanagram(lis, anaind):
result = []
llis = lis[:]
while llis:
anaind, indx = divmod(anaind, len(llis))
result.append(llis.pop(indx))
return result
I don't think the fact() calls in your pickana are
correct -- I think you need a divmod(ana,len(lis))
in your version too (or equivalently separate uses
of operators / and % as you have, but divmod seems
clearer to me in this case).
> I'm sure some people here could do any of the above
> with two-liners; I'd be interested to see those!
pickanagram seems nice & readable, but if squeezing
functionality into fewer statements were the goal,
something might be feasible. Usual disclaimers: I
am *NOT* advocating the following as good, or even
halfway sensible, Python programming, just playing
with Joe's "challenge":-).
Basically, the body of pickanagram is CLOSE to a list
comprehension (a single statement) plus the copy of
lis (to make pickanagram nondestructive on its argument!);
this suggests we need to check if we CAN indeed make it
into a list-comprehension. Moving closer:
def pick1(lis, anaind):
llis = lis[:]
result = []
for i in range(len(lis), 0, -1):
anaind, indx = divmod(anaind, i)
result.append(llis.pop(indx))
return result
This is now very close to list-comprehension form
result = []
for <whatever1>
result.append(<whatever2>)
except for the rebinding of anaind in the
first statement of the for's body, which a list
comprehension can't do *directly*. HOWEVER, a
list comprehension CAN be nested:
result = []
for <whatever1>
for <whatever2>
result.append(<whatever3>)
and a for-statement (or for-clause in a lc) IS
able to re-bind variables! So...:
def pick2(lis, anaind):
llis = lis[:]
result = []
for i in range(len(lis), 0, -1):
for anaind, indx in [divmod(anaind, i)]:
result.append(llis.pop(indx))
return result
and now we ARE in list-comprehensionable form, so:
def pick3(lis, anaind):
llis = lis[:]
return [llis.pop(indx)
for i in range(len(lis), 0, -1)
for anaind, indx in [divmod(anaind, i)]]
Well, it's now two LOGICAL lines. So, it's just an
issue of squeezing down whitespace and name lengths:
def pick4(lis, i):
l = lis[:]
return[l.pop(j)for k in range(len(l),0,-1)for i,j in[divmod(i,k)]]
and we can, if need be, squeeze a couple more characters
by giving up divmod too:
def pick5(lis, i):
l = lis[:]
return[l.pop(j)for k in range(len(l),0,-1)for i,j in[(i/k,i%k)]]
Now THIS is what I mean by "obsessed with shortening one's code"...
Hmmm -- I don't think I'll sign *THIS* post...!!!
More information about the Python-list
mailing list