# 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
...
> # 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...!!!

```