View Full Version : automatically rename non-unique nodes?


cgbeige
06-25-2011, 04:56 PM
i sometimes get items that have been duplicated and don't have unique names. They trip up my batch rendering script and I'm wondering if there's a way to weed these out and automatically rename them.

zoharl
06-25-2011, 05:33 PM
Define an object that contains the short name and the full name of an object:

class obj:
short_name = []
long_name = []


For each object in your scene, create such an object, and add it to a list.
Sort the list according to the short name. Go through the list, and whenever you find two consecutive items with the same short name, rename the second item to a name of an object that would appear later in the sorted list (e.g. add '1' to the end of the name), and move the item to its sorted place in the list (forward). Continue your check from the first item.

Alternatively you could implement the same idea with two arrays, without using objects.

mlefevre
06-25-2011, 06:44 PM
Probably a daft way to go about it but..

import maya.cmds as cmds

objs = cmds.ls()
copy = [x.rpartition('|')[2] for x in objs]

for i in range(len(copy)):
startIndex = 0
copyCount = copy.count(copy[i])
if copyCount > 1:
dup = copy[i]
for j in range(copyCount):
index = copy.index(dup, startIndex)
copy[index] = cmds.rename(objs[index], (dup + '_' + str(j)))
startIndex = index+1

Doesn't include namespaces.

NaughtyNathan
06-25-2011, 07:01 PM
you don't need to go through all that rigamarole.
If you simply `ls` using short names maya will return short names but not non-unique names, so anything in that list that contains a "|" (the DAG path Separator) is not uniquely named.
Here's some example MEL (as I assume you are still a MEL man Dave..?)
string $allDagNodes[] = `ls -sn -dag`;
for ($node in $allDagNodes)
if (`gmatch $node "*|*"`)
print ($node+" is not uniquely named\n");

# python:
allDagNodes = cmds.ls(sn=1,dag=1)
nonUnique = [ node for node in allDagNodes if '|' in node ]
the trick to uniquely naming a node is not checking it against existing names, but using a built in Maya feature. If you create a DG node on the scene root and give it a name, Maya will only return unique names, so simply create an arbitrary node and give it the same name as your non-unique node, and it will return a uniquely named variation.
string $unique = `createNode "unknown" -n "pCube3"`;
// Result: pCube17
if the returned name happens to be identical to the one you gave then you know it's a unique name.
:nathaN

zoharl
06-25-2011, 07:18 PM
Nice trick, I should have thought about at least one of them, but I was in brute force mode.

mlefevre
06-25-2011, 08:12 PM
the trick to uniquely naming a node is not checking it against existing names, but using a built in Maya feature. If you create a DG node on the scene root and give it a name, Maya will only return unique names, so simply create an arbitrary node

It's a nice feature that maya gives a unique name to a node upon creation, but to have to create and delete a node for each node with a non-unique name seems somewhat innefficient. Or am I not understanding it? :o

zoharl
06-25-2011, 09:12 PM
I don't think that the emphasis in this task is on a killer performance, and how much creating and deleting a dummy node should cost anyway?!

BTW mlefevre, I think your code is imperfect. What would happen if your copy list already contains a member dup + '_' + str(j) ?
For example: copy = ['a', 'a', 'a_0']

After fixing this, if you are interested in complexity, compare the complexity of your algorithm to mine (something like O(n^2) vs O(nlogn))

;)

mlefevre
06-25-2011, 09:28 PM
I don't think that the emphasis in this task is on a killer performance, and how much creating and deleting a dummy node should cost anyway?!

heh, you're probably right. It just seems a bit odd to create a node only to delete it.

BTW mlefevre, I think your code is imperfect. What would happen if your copy list already contains a member dup + '_' + str(j) ?
For example: copy = ['a', 'a', 'a_0']

I just stumbled through it, so no doubt it is. I'm not quite understanding what you're getting at though. Would you mind posting a full working example on how to break it. Just for fun!

After fixing this, if you are interested in complexity, compare the complexity of your algorithm to mine (something like O(n^2) vs O(nlogn))

;)

That's all well and good, but I failed my maths at school, and I've no idea what all that means.
I'm more than happy for you to teach me though ;)

zoharl
06-25-2011, 10:01 PM
That's all well and good, but I failed my maths at school, and I've no idea what all that means.
I'm more than happy for you to teach me though

Not important here, don't bother yourself with it. But the general idea is since you didn't sort your array, you'll have to go all over it to test for duplicates each time, while I don't. It's a factor of the size of an array concerning performance.

Would you mind posting a full working example on how to break it

I believe I did, but I'll be more specific. In a new scene execute:

createNode transform -name a_0;
createNode transform -name a -p a_0;
createNode transform -name a -p a;


:eek:

mlefevre
06-25-2011, 10:13 PM
I believe I did, but I'll be more specific. In a new scene execute:

createNode transform -name a_0;
createNode transform -name a -p a_0;
createNode transform -name a -p a;


:eek:

You broke it! :( ....Okay, I'll take you up on on the challenge!

mlefevre
06-25-2011, 10:59 PM
yey, managed to shorten it a bit more. :)

Break it if ye dare Zoharl! :buttrock:

import maya.cmds as cmds

objs = [x for x in cmds.ls(shortNames=True) if '|' in x]
objs.sort(key=lambda x : x.count('|'))
objs.reverse()
for i in range(len(objs)):
cmds.rename(objs[i], objs[i].replace('|', ''))

# proof
if not len([x for x in cmds.ls(shortNames=True) if '|' in x]):
print 'no non-unique names :)'

cgbeige
06-26-2011, 12:48 AM
awesome - thanks so much.

zoharl
06-26-2011, 08:23 AM
Break it if ye dare Zoharl! :buttrock:

We will still stay friends afterwards, right?

createNode transform -name a;
createNode transform -name a -p a;
createNode transform -name aa;


:curious:

mlefevre
06-27-2011, 04:32 PM
We will still stay friends afterwards, right?

Hehe, ofcourse :)

Talk about opening a can of worms. On much reflection, Nathans suggestion definately seems the most efficient. I stuck at though just for kicks so here's another attempt. Screw the performance..I just want it to work now.

import maya.cmds as cmds
import re

objs = [cmds.ls(x, long=True)[0] for x in cmds.ls(shortNames=True, type='transform') if '|' in x]
objs.sort(key=lambda x : x.count('|'), reverse=True)
copy = [x.rpartition('|')[2] for x in objs]

for i in range(len(objs)):

num = [int(x) for x in list(set([re.findall("[0-9]*$", x)[0] for x in cmds.ls(copy[i] + '_*')])) if x.isdigit()]

if len(num):
num = max(num)+1
else:
num = 1

cmds.rename(objs[i], copy[i] + '_' + str(num))

zoharl
06-27-2011, 08:53 PM
Great :thumbsup:

I still don't understand the function of this line (maybe for luck?):

objs.sort(key=lambda x : x.count('|'), reverse=True)

Nathan with his trick used maya inner mechanism to solve the unique naming for him. What you did is more interesting, you implemented this mechanism yourself.

A recap of your algorithm:

1. Get the names of all objects with the same short name.
2. Add for each such name a suffix of '_' and a number. For the number to be unique, you look for all the objects with this pattern (name_#), and set your number to the largest number in existence + 1.

mlefevre
06-27-2011, 10:06 PM
Great :thumbsup:

I still don't understand the function of this line (maybe for luck?):

objs.sort(key=lambda x : x.count('|'), reverse=True)

hehe, thanks! To rename an object, I had to supply the full path. If I renamed the parent before renaming the child, the path becomes invalid so I had to sort them with that line.

zoharl
06-27-2011, 10:59 PM
Nice, I didn't consider this point.

rgkovach123
05-10-2012, 07:47 PM
generating a new unique name is easy with MEL/Python.

rename "|group1|pCube1" "|group1|pCube#"

will generate the next unique number for the base name "pCube"

using the "#" in a rename operation tells Maya to use it's internal mechanism for generating unique names.

no need to write code to look for valid numeric suffixes.

Mondo
05-10-2012, 08:25 PM
generating a new unique name is easy with MEL/Python.

rename "|group1|pCube1" "|group1|pCube#"

will generate the next unique number for the base name "pCube"

using the "#" in a rename operation tells Maya to use it's internal mechanism for generating unique names.

no need to write code to look for valid numeric suffixes.

So awesome! :bowdown:

zoharl
05-10-2012, 09:37 PM
Nice. :thumbsup:

And I believe you meant

rename "|group1|pCube1" "pCube#"

Although still you need to parse the number out of the object name. So Nathan's method still might be an easier general solution.

mlefevre
05-11-2012, 12:38 AM
generating a new unique name is easy with MEL/Python.

rename "|group1|pCube1" "|group1|pCube#".

Tasty solution, thanks for sharing :) I'm sure I've seen this before as well... Doh!
Both yours & Nathans solutions are deffo the best way to go. My solution is ridiculous, but it was a fun journey. ;)

rgkovach123
05-11-2012, 03:06 PM
Although still you need to parse the number out of the object name. So Nathan's method still might be an easier general solution.

string parsing is pretty easy in python, can also be done with MEL... the regular expressions came from this page:

http://ewertb.soundlinker.com/mel/mel.094.php


import re
import maya.cmds as cmds
name = '|group1|pCube1'

m = re.compile("[^|]*$").search(name) # extract the base name
shortname = m.group(0)

m2 = re.compile(".*[^0-9]").match(shortname) # extract the numeric suffix
if m2:
stripSuffix = m2.group(0)
else:
stripSuffix = shortname

cmds.rename(name, (stripSuffix + "#"))

zoharl
05-11-2012, 05:09 PM
What would be the result for

name = 'p1Cube1'

? ;)

rgkovach123
05-11-2012, 07:42 PM
What would be the result for

name = 'p1Cube1'

? ;)

"p1Cube2" if it's available. the regex only strips numbers from the end of the string, leaving numbers embedded in the middle of the string intact.

zoharl
05-11-2012, 08:08 PM
My bad, misread your regex. :arteest:

CGTalk Moderation
05-11-2012, 08:08 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.


1