I'm learning Python to use wMaya - a 3D graphics app.
While reverse engineering some code, I found a thread here which explains "list comprehension". The code I'm analyzing uses that, so I attempted to deconstruct it, but I can't reproduce the same results using a for loop.
I have a list:

print tmpJnts
[nt.Joint(u'joint1'), nt.Joint(u'joint2'), nt.Joint(u'joint3'), nt.Joint(u'joint4'), nt.Joint(u'joint5')]

I was shown how to convert it to a string using list comprehension:

jntStringList = ' '.join([j.name() for j in tmpJnts])
print jntStringList
joint1 joint2 joint3 joint4 joint5

I'm curious how to use a for loop to accomplish this. I've tried a few approaches, but no luck:

for j in tmpJnts:
	print j.name()
	print (' '.join([j.name()] ) )
	print (' '.join(j.name() ) ) # Without brackets, the string is treated as a list: j o i n t 5
	jntStringList2.append(' '.join([j.name()])) #Append will create a new list item for each iteration
	jntStringList3 += (' ' + j.name() )  #
joint1
joint1
j o i n t 1
joint2
joint2
j o i n t 2
joint3
joint3
j o i n t 3
joint4
joint4
j o i n t 4
joint5
joint5
j o i n t 5

print jntStringList2
[u'joint1', u'joint2', u'joint3', u'joint4', u'joint5']
print jntStringList3
[u' ', u'j', u'o', u'i', u'n', u't', u'1', u' ', u'j',...]

Can anyone explain how to do use a loop to convert a list to a string in this case?
Thanks much.

Recommended Answers

All 8 Replies

For me it should be (even You did not send definition of j object):

jntStringList=''
for j in tmpJnts:
    jntStringList+=j.name()+' '
jntStringList=jntStringList[:-1] ## remove ' ' in the end

Tonyjv's idea works just fine, but I have a pattern I use for languages that don't offer the string.join(list) function. Here it is in Python, which doesn't need it:

def sjoin(sep, aList):
  ret = ''
  s = ''
  for item in aList:
    ret = "%s%s%s"%(ret,s,item)
    # or ret = ret + s + str(item)
    s = sep
  return ret

In light of recent homework questions: As an exercise for the reader: How would you write recursive_sjoin ?

In some languages, under some circumstances, assigning s = sep in the loop is cheaper than testing to see if you are in the loop for the first (or last) time. Most languages and circumstances make it difficult to tell which is better: Both techniques are quite efficient. Tonyjv's technique, which would need to be slightly modified to allow any string to be the separator, might be fastest of all, especially for a large list. I don't know because I haven't done any tests for that one.

And, by the way: This isn't list comprehension. Comprehension creates a list from some form of generator. http://docs.python.org/tutorial/datastructures.html#list-comprehensions

That link qualifies

>>> [3*x for x in vec]

as list comprehension so I think poster was right to call

jntStringList = ' '.join([j.name() for j in tmpJnts])

a list comprehension also.

The speed question becomes even more interesting if you start to use module psyco (Python 2 only), try pypy (http://pypy.org/) (python 2.5) or even Shedskin compilation for python subset (http://code.google.com/p/shedskin/ windows no longer supported as of version 0.4) to C++ to speed things up. You may see my old post for one surprising observation where very small difference (keeping one variable module variable, not passed recursively around) made huge difference in performance. Has by the way anybody got Unladen swallow to compile in Windows? I got until compiling clang, then got stuck (http://code.google.com/p/unladen-swallow/)

My fault for bad reference to "'this' (isn't list comprehension)". By 'this' I referred to the string join part, not the list creation in the initial code, but I did not make it clear.

Thanks for the coding assistance and the explanations.
Tony:
The list is initially created using a procedure in Maya (making a list of the selected items).
Here is a printout:
print tmpJnts
[nt.Joint(u'joint1'), nt.Joint(u'joint2'), nt.Joint(u'joint3'), nt.Joint(u'joint4'), nt.Joint(u'joint5')]

Tony's approach did not work. For some reason, it is tricky to get the name() of the items in the list and add a separator to them.

griswolf's approach did work, though I'm not sure why. As I've looked into it further, I see that the items in the list are objects (3D joints in this case). If listed individually, they return their name, though it is not a string.

print tmpJnts[0]
#joint1
print len(tmpJnts[0]) # Error - 'Joint' has no len()
print str(tmpJnts[0])
#joint1
print len(str(tmpJnts[0]))
#6

What I don't quite get is, why doesn't:
print tmpJnts[0]
return:
nt.Joint(u'joint1')

Sometimes it takes awhile for this stuff to sink in.
Thanks again for the help.
Here's the results of your code:

# TonyJV
jntStringList4 = []
for j in tmpJnts:
	print j.name()
	jntStringList4 += j.name()+' '
jntStringList4 = jntStringList4 [:-1] ## remove ' ' in the end

print jntStringList4
joint1
joint2
joint3
joint4
joint5
[u' ', u'j', u'o', u'i', u'n', u't', u'1' ... u't', u'5']

# griswolf
jntStringList5 = []
def sjoin(sep, aList):
  ret = ''
  s = ''
  for item in aList:
    ret = "%s%s%s"%(ret,s,item)
    # or ret = ret + s + str(item)
    s = sep
  return ret
jntStringList5 = sjoin (' ', tmpJnts)
print jntStringList5
print len(jntStringList5)
joint1 joint2 joint3 joint4 joint5

Try adding str to my loop as the print worked

jntStringList4 += str(j.name())+' '

If did not work change str to repr and prove again.

Tony:
Neither worked - same result as before.
I am curious why that is happening, but I have a way to accomplish my task, so I'm happy.
However, if you want me to try anything else, let me know.
Thanks.

Must be buggy implementation of __str__ and __repr__ function in j objects definition, oh, never mind.

BTW mark the thread solved.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.