Which is faster:
- Getting object by piece of it’s name
- Getting object by UserObject attribute
Which is faster:
I’m going to hazard a guess that it will be about the same - both are object attributes at the same level, so searching for either will probably take about the same time…
OK, a simple test:
I created a box, give it a name “box_one” and also set a user text “box_one” under a key “searchtest”
I then ran the following script -
First it times one million searches of the object name to see if it contains “one”
Then it does the same to see if the user string key “searchtest” contains “one”
import rhinoscriptsyntax as rs
import scriptcontext as sc
import Rhino, time
objID=rs.GetObject()
#object has object name 'box_one'
#object has user text 'box_one' stored under key searchtest
#will search if object name or user string contains "one"
obj=rs.coercerhinoobject(objID)
fragment="one"
st1=time.time()
name_search_count=0
for i in range(1000000):
name=obj.Attributes.Name
if fragment in name: name_search_count+=1
print "Name search time={}, Found {}".format(time.time()-st1,name_search_count)
st2=time.time()
string_search_count=0
for i in range(1000000):
ustr=obj.Attributes.GetUserString("searchtest")
if fragment in ustr: string_search_count+=1
print "String search time={}, Found {}".format(time.time()-st2,string_search_count)
The results are:
Name search time=1.56773376465, Found 1000000
String search time=1.72177001953, Found 1000000
A difference of less than 0.2 seconds in a million searches is not extremely significant IMO…
You probably need to run that test on a 3dm that has a several thousand objects where only the very last object has the searched for data.
If you want to search really fast and object name is a good key for you then you should look into ObjectEnumeratorSettings().
Test:
randomnames.py
test_search_speed.py
I get as output:
Name search time=0.227386474609, Found 1
String search time=0.262298583984, Found 1
Enumerator settings time=0.0179595947266, Found 1
The scripts:
randomnames.py
import random, string
import scriptcontext as sc
def randomword(length):
letters = string.ascii_lowercase
return ''.join(random.choice(letters) for i in range(length))
obs = [o for o in sc.doc.Objects]
for o in obs[:-1]:
o.Attributes.Name = randomword(15)
o.Attributes.SetUserString("somelongkey", randomword(15))
o.CommitChanges()
o = obs[-1]
o.Attributes.Name = "longnametosearchfor"
o.Attributes.SetUserString("somelongkey", "longnametosearchfor")
o.CommitChanges()
test_search_speed.py
:
_count=0
for i in range(1):
for obj in sc.doc.Objects:
name=obj.Attributes.Name
if fragment in name: name_search_count+=1
print "Name search time={}, Found {}".format(time.time()-st1,name_search_count)
st2=time.time()
string_search_count=0
for i in range(1):
for obj in sc.doc.Objects:
ustr=obj.Attributes.GetUserString(key)
if fragment in ustr: string_search_count+=1
print "String search time={}, Found {}".format(time.time()-st2,string_search_count)
st3=time.time()
enumeratorsettings = Rhino.DocObjects.ObjectEnumeratorSettings()
enumeratorsettings.NameFilter=fragment
obs = [o for o in sc.doc.Objects.GetObjectList(enumeratorsettings)]
print "Enumerator settings time={}, Found {}".format(time.time()-st3, len(obs))
Thanks Nathan,
Does this enumeratorsettings
look into usertext attributes as well? Can I make it look there?
My models where I need this have over 20k objects inside. Also I need to check for name of the object and 5 usertext attributes.
in the second case I have less objects between 5k and 10k, but I have over 10 usertext attributes on each object.
ObjectEnumeratorSettings doesn’t have an entry for user text that I could find.
The test I posted above has you create 10k objects, and creates the worst case scenario by having the last object be the one you need.
Searching name through Attributes is 0.22s, string from user data text is 0.26s.
It isn’t so much the accessing of those bits in Attributes, but rather the traversing of the objects in the document.
There is a method which allows to FindByUserString
without iterating all objects in python. Maybe you could use it to search for one of the required user strings and filter
the results using the other required attributes.
_
c.
Apparently there it is also in scriptcontext
sc.doc.Objects.FindByUserString()
I think the developer pages always quote the latest version number (i.e. does it work now), not the first version from which the method started working.
yes, it works.