NEWBIE: map | zip | list comp

E

engsolnom

Hello again...hope everyone had a great New Year...:)

In the quest to learn more about Python, I decided to create an arbitrary sequence,
then march each member through a 'field' of each of the members in turn, and just to complicate it a
bit, make the length of the field user defined.
Hard to explain...an example might serve:

10000
01000
00100
.
.
00009
01111
10111
11011
.
.
21111
12111
11211
and so forth.

The only coding I could come up with is:

base_seq = 'ABCD'
length = 6

for char_1 in base_seq: # Loop thru the set char_1 at a time
for char_2 in base_seq: # Loop thru the seq again for each char_1
if char_2 == char_1: continue # Don't march 'A' thru a field of 'A's
for ix in range(length): # Now march char_2 thru a field of char_1's
print (char_1 * length)[:ix] + char_2 + (char_1 * length)[ix:-1]

which, as you can see, has three nested FOR loops. I played with map, zip and list comps a bit, but
couldn't figure out how to compress the above code. Am I barking up the wrong Python tree?

Thanks......Norm
 
T

Terry Reedy

Hello again...hope everyone had a great New Year...:)

In the quest to learn more about Python, I decided to create an arbitrary sequence,
then march each member through a 'field' of each of the members in turn, and just to complicate it a
bit, make the length of the field user defined.
Hard to explain...an example might serve:

10000
01000
00100
.
.
00009
01111
10111
11011
.
.
21111
12111
11211
and so forth.

The only coding I could come up with is:

base_seq = 'ABCD'
length = 6

for char_1 in base_seq: # Loop thru the set char_1 at a time
for char_2 in base_seq: # Loop thru the seq again for each char_1
if char_2 == char_1: continue # Don't march 'A' thru a field of 'A's
for ix in range(length): # Now march char_2 thru a field of char_1's
print (char_1 * length)[:ix] + char_2 + (char_1 *
length)[ix:-1]

Move the constant char_1*length outside of the two inner loops, or else
multiple by the actual needed length instead of making too much and
slicing.
which, as you can see, has three nested FOR loops. I played with map, zip and list comps a bit, but
couldn't figure out how to compress the above code.

You mean something like (untested):

[char_1*ix + char_2 + char_1*(length - ix -1) for char_1 in base_seq
for char_2 in base_seq if char_1 != char_2 for ix in range(length)]
Am I barking up the wrong Python tree?

I think so. Consider how long it took you to write clear conprehensible
code using Python's significant indentation *feature* and how long it took
you to not successfully get rid of it and how long it took you to convince
yourself that my no-indent perversion produces the same items (though in a
list), if indeed it does. In my view, expressions should be only as long
as can be grokked in one mental gulp, and I think above overdoes it a bit.
Of course, the humancode quality can be restrored by writing it more
clearly as

[char_1*ix + char_2 + char_1*(length - ix -1)
for char_1 in base_seq
for char_2 in base_seq
if char_1 != char_2
for ix in range(length)]

in which case one has just moved the last line to the top and avoided
result=[] and result.append().

Terry J. Reedy
 
S

sdd

...

for char_1 in base_seq: # Loop thru the set char_1 at a time
for char_2 in base_seq: # Loop thru the seq again for each char_1
if char_2 == char_1: continue # Don't march 'A' thru a field of 'A's
for ix in range(length): # Now march char_2 thru a field of char_1's
print (char_1 * length)[:ix] + char_2 + (char_1 * length)[ix:-1]
which, as you can see, has three nested FOR loops. I played with map, zip and list comps a bit, but
couldn't figure out how to compress the above code. Am I barking up the wrong Python tree?

I'd think so. The 3-level nest looks fine (clear) to me.
The things I might change about the above code:

for char_1 in base_seq:
copies = char_1 * (length-1)
for char_2 in base_seq:
if char_2 != char_1:
# For every pair of non-matching characters
for ix in range(length):
# March char_2 thru a field of char_1's
print copies[:ix] + char_2 + copies[ix:]

or:

for char_1 in base_seq:
for char_2 in base_seq:
if char_2 != char_1:
# For every pair of non-matching characters
for ix in range(length):
# March char_2 thru a field of char_1's
print char_1 * ix + char_2 + char_1 * (length-1-ix)

The point is to go for clarity, not brevity. I'd think about
better names than char_1 and char_2, however.


-Scott David Daniels
(e-mail address removed)
 
M

MetalOne

The following produces the same result but in a 2 dimensional list.
However, it is darn near impossible to read.

print map(lambda x:
map(lambda (c1,c2):
map(lambda ix: (c1*length)[:ix]+c2+(c1*length)[ix:-1], range(length)),
filter(lambda (c,d): c!=d, map(lambda y: (x,y), base_seq))), base_seq)


for base_seq = "ABCD"
The (x,y) pairs produced are
(A,A), (A,B), (A,C), (A,D),
(B,A), (B,B), (B,C), (B,D), ...

The filter removes the duplicate pairs (A,A),(B,B),(C,C),(D,D)

for (c1,c2) in [(A,B), (A,C), (A,D)] the rotation function gets applied.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,174
Messages
2,570,940
Members
47,486
Latest member
websterztechnologies01

Latest Threads

Top