[Closed] Challenge: Make all Object Names Unique
I think this is a way to do it… although this would make anything capitalized become lowercase.
--Setup
for i = 1 to 100 do
(
box name:("TestBox_" + (random 1 20) as string)
)
for i = 1 to 100 do
(
box name:("testbox_" + (random 1 20) as string)
)
--This function looks through an array of objects and finds the naming clashes and renames them to unique names, can easily be modified for selection etc....
fn makeObjectNamesUnique aObjs =
(
theObjs = sort(for o in aObjs collect (toLower o.name))
matches = #()
for i = 1 to (theObjs.count - 1) where theObjs[i] == theObjs[i + 1] do appendIfUnique matches theObjs[i]
for m in matches do
(
for o in aObjs where (toLower o.name) == m do o.name = uniqueName m
)
)
makeObjectNamesUnique objects
--makeObjectNamesUnique selection
This method fails, Dave.
Try a scene with your “TestBox_”, add 7 Spheres, and rename Sphere002 to Sphere001.
Run your code and you’ll get 2 “sphere005” and 2 “sphere006”.
i don’t think your solution is good enough. it would be good to have highest index is equal to number of dups.
uniqueName make index 004 for example in case where 001 and 003 already exist. i would do something like i’ve showed above.
I’m not too bothered by that, I just want to make sure when using later scripts which get objects by name that I don’t have any clashes.
well…
for obj in objects do
(
dups = getnodebyname obj.name all:on
if dups.count > 0 do for dup in dups do dup.name = uniquename (dup.name as name)
)
I really don’t know what happens… where DenisT use 2 lines, I use over 100!!
Well, this is my proposal. It’s based in finding the “index” of the objects with duplicated names through C#.
After that, it use this index array to rename these objects and, additionnally, return original names (with upper and lower case) to objects.
Not quick at all, not very nice structure, but it works.
P.S.: You should create an example with additionnal names, not only “TestBox_”, because I’ve found some problems with the other codes (renaming what you don’t have to).
global uniqueNamesSearch = "uniqueNamesSearch"
(
classStr = "
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Max;
public class uniqueNamesSearch
{
static public IGlobal global = GlobalInterface.Instance;
public string[] objNames;
public int[] index;
public int numObjs;
public int[] repeatedIndex;
/// CONSTRUCTOR
public uniqueNamesSearch(string[] MXSobjnames)
{
numObjs = MXSobjnames.Length;
objNames = new string[numObjs];
index = new int[numObjs];
for (int k = 0; k < numObjs; k++)
{
objNames[k] = MXSobjnames[k].ToLower();
index[k] = k + 1;
}
Array.Sort(objNames, index);
repeatedIndex = findRepeated();
}
public int[] findRepeated()
{
List<int> repeated = new List<int>();
for (int k = 1; k < numObjs; k++)
{
if (objNames[k - 1] == objNames[k])
{
repeated.Add(index[k-1]);
repeated.Add(index[k]);
}
}
return repeated.Distinct().ToArray();
}
}
"
compilerParams = dotnetobject "System.CodeDom.Compiler.CompilerParameters"
dotnet.setlifetimecontrol compilerParams #dotnet
compilerParams.ReferencedAssemblies.Add("System.dll");
compilerParams.ReferencedAssemblies.Add("System.Core.dll");
compilerParams.ReferencedAssemblies.Add((getdir #maxroot) + @"Autodesk.Max.dll");
compilerParams.GenerateInMemory = on
csharpProvider = dotnetobject "Microsoft.CSharp.CSharpCodeProvider"
compilerResults = csharpProvider.CompileAssemblyFromSource compilerParams #(classStr)
dotnet.setlifetimecontrol compilerResults #dotnet
if (compilerResults.Errors.Count > 0 ) then
(
local errs = stringstream ""
for i = 0 to (compilerResults.Errors.Count-1) do
(
local err = compilerResults.Errors.Item[i]
format "Error:% Line:% Column:% %
" err.ErrorNumber err.Line err.Column err.ErrorText to:errs
)
format "%
" errs
undefined
)
)
(
tss = timestamp()
objNames = for o in objects collect o.name
findRepeatedObjects = dotnetobject uniqueNamesSearch objNames
repeatedIndex = findRepeatedObjects.repeatedIndex
lowerNames = findRepeatedObjects.objNames
for i = 1 to objects.count do objects[i].name = toLower objects[i].name
for i in repeatedIndex do objects[i].name = uniqueName objects[i].name
for i = 1 to objects.count where findItem repeatedIndex i == 0 do objects[i].name = objNames[i]
for i in repeatedIndex do
(
realName = objNames[i]
uniqueLowerName = objects[i].name
baseName = trimright uniqueLowerName "0123456789"
uniqueIndex = (substring uniqueLowerName (baseName.count+1) -1)
finalUniqueName = (trimright realName "0123456789") + uniqueIndex
objects[i].name = finalUniqueName
)
tef = timestamp()
print ("Total time: " + ((tef-tss)/1000.0) as string + " seconds")
)
My code cleaned:
global uniqueNamesSearch = "uniqueNamesSearch"
(
classStr = "
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
public class uniqueNamesSearch
{
public int[] index;
public int numObjs;
public int[] repeatedIndex;
/// CONSTRUCTOR
public uniqueNamesSearch(string[] MXSobjnames)
{
numObjs = MXSobjnames.Length;
string[] objNames = new string[numObjs];
index = new int[numObjs];
for (int k = 0; k < numObjs; k++)
{
objNames[k] = MXSobjnames[k].ToLower();
index[k] = k + 1;
}
Array.Sort(objNames, index);
repeatedIndex = findRepeated(objNames);
}
public int[] findRepeated(string[] objNames)
{
List<int> repeated = new List<int>();
for (int k = 1; k < numObjs; k++)
{
if (objNames[k - 1] == objNames[k])
{
repeated.Add(index[k-1]);
repeated.Add(index[k]);
}
}
return repeated.Distinct().ToArray();
}
}
"
compilerParams = dotnetobject "System.CodeDom.Compiler.CompilerParameters"
dotnet.setlifetimecontrol compilerParams #dotnet
compilerParams.ReferencedAssemblies.Add("System.dll");
compilerParams.ReferencedAssemblies.Add("System.Core.dll");
compilerParams.GenerateInMemory = on
csharpProvider = dotnetobject "Microsoft.CSharp.CSharpCodeProvider"
compilerResults = csharpProvider.CompileAssemblyFromSource compilerParams #(classStr)
dotnet.setlifetimecontrol compilerResults #dotnet
)
(
tss = timestamp()
objNames = for o in objects collect o.name
findRepeatedObjects = dotnetobject uniqueNamesSearch objNames
repeatedIndex = findRepeatedObjects.repeatedIndex
for o in objects do o.name = toLower o.name
for i in repeatedIndex do objects[i].name = uniqueName objects[i].name
for i = 1 to objects.count where findItem repeatedIndex i == 0 do objects[i].name = objNames[i]
for i in repeatedIndex do
(
uniqueLowerName = objects[i].name
baseName = trimright uniqueLowerName "0123456789"
uniqueIndex = (substring uniqueLowerName (baseName.count+1) -1)
objects[i].name = (trimright objNames[i] "0123456789") + uniqueIndex
)
tef = timestamp()
print ("Total time: " + ((tef-tss)/1000.0) as string + " seconds")
)