迭代大型unicode列表需要很长时间?

时间:2014-10-31 19:25:08

标签: list python-2.7 unicode iteration maya

我正在使用Autodesk Maya程序。 我已经制作了一个命名约定脚本,它将相应地命名某个约定中的每个项目。但是我每次都在场景中列出它,然后检查所选名称是否与场景中的任何当前名称匹配,然后我重命名它并在场景中再次重新检查,如果有重复。

然而,当我运行代码时,可能需要长达30秒到一分钟或更长时间才能完成所有操作。起初我不知道是什么让我的代码运行缓慢,因为它在相对较低的场景量下工作正常。但是当我将打印语句放入检查场景代码时,我发现检查场景中的所有项目需要很长时间,并检查重复项。

ls()命令提供场景中所有项目的unicode列表。这些项目可能相对较大,如果场景甚至有适量的项目,则可达到一千或更多,正常场景将比我现在的测试场景大几倍(在此列表中有大约794个项目) )。

这应该花这么久吗?我用的方法是用来比较效率低下的东西吗?我不知道该怎么做,代码占用了太多时间,我也想知道它是否可能是代码中的任何其他内容,但这似乎可能就是它。

以下是一些代码。

class Name(object):
    """A naming convention class that runs passed arguments through user
    dictionary, and returns formatted string of users input naming convention.
    """

    def __init__(self, user_conv):
        self.user_conv = user_conv
        # an example of a user convention is '${prefix}_${name}_${side}_${objtype}'

    @staticmethod
    def abbrev_lib(word):
        # a dictionary of abbreviated words is here, takes in a string
        # and returns an abbreviated string, if not found return given string


    @staticmethod
    def check_scene(name):
        """Checks entire scene for same name. If duplicate exists,

        Keyword Arguments:
        name -- (string) name of object to be checked
        """

        scene = ls()
        match = [x for x in scene if isinstance(x, collections.Iterable)
                        and (name in x)]
        if not match:
            return name
        else:
            return ''

    def convert(self, prefix, name, side, objtype):
        """Converts given information about object into user specified convention.

        Keyword Arguments:
        prefix -- what is prefixed before the name
        name -- name of the object or node
        side -- what side the object is on, example 'left' or 'right'
        obj_type -- the type of the object, example 'joint' or 'multiplyDivide'
        """
        prefix = self.abbrev_lib(prefix)
        name = self.abbrev_lib(name)
        side = ''.join([self.abbrev_lib(x) for x in side])
        objtype = self.abbrev_lib(objtype)
        i = 02
        checked = ''
        subs = {'prefix': prefix, 'name': name, 'side':
            side, 'objtype': objtype}
        while self.checked == '':
            newname = Template (self.user_conv.lower())
            newname = newname.safe_substitute(**subs)
            newname = newname.strip('_')
            newname = newname.replace('__', '_')
        checked = self.check_scene(newname)
        if checked == '' and i < 100:
            subs['objtype'] = '%s%s' %(objtype, i)
            i+=1
        else:
            break
    return checked

2 个答案:

答案 0 :(得分:1)

你经常多次这样做吗?您可能会在while self.checked ==''内为每次迭代拖曳几百或几千个项目的列表,这可能是罪魁祸首。 Maya中的FWIW打印速度也很慢,特别是如果你要打印一个很长的列表 - 所以这样做很多次肯定会很慢。无论如何。

我会尝试一些方法来加快速度:

  1. 一次将您的搜索限制为一种类型 - 如果您现在只关心MultiplyDivide,为什么要浏览数百个随机节点?
  2. 使用集合或字典进行搜索,而不是列表 - 集合和字典使用散列集,并且查找速度更快
  3. 如果您担心维持命名对话,请确保将其设计为抵抗Maya的默认行为,即附加数字后缀以保持名称唯一。任何不支持这一点的命名约定都会一直困扰着对手,因为你不能阻止Maya在正常的业务过程中这样做。另一方面,如果您将其用于区分实例,则根本不需要进行任何统一 - 只需对对象使用rename()并捕获结果。缺点是Maya不会重命名为全局唯一性,只有本地 - 所以如果你想为不是兄弟姐妹的东西制作唯一的节点名,你必须自己做。
  4. 这是一些用于查找唯一节点名称的廉价代码:

    def get_unique_scene_names (*nodeTypes):
        if not nodeTypes:
            nodeTypes = ('transform',)
        results = {}
        for longname in cmds.ls(type = nodeTypes, l=True):
            shortname = longname.rpartition("|")[-1]
            if not shortname in results:
                results[shortname] = set()
            results[shortname].add(longname)    
        return results
    
    def add_unique_name(item, node_dict):
        shortname = item.rpartition("|")[-1]
        if shortname in node_dict:
            node_dict[shortname].add(item)
        else:
            node_dict[shortname] = set([item])
    
    def remove_unique_name(item, node_dict):
        shortname = item.rpartition("|")[-1]
        existing  = node_dict.get(shortname, [])
        if item in existing:
            existing.remove(item)
    
    
    def apply_convention(node, new_name, node_dict):
        if not new_name in node_dict:
            renamed_item = cmds.ls(cmds.rename(node, new_name), l=True)[0]
            remove_unique_name(node, node_dict)
            add_unique_name ( renamed_item, node_dict)
            return renamed_item
        else:
            for n in range(99999):
                possible_name = new_name + str(n + 1)
                if not possible_name in node_dict:
                    renamed_item =  cmds.ls(cmds.rename(node, possible_name), l=True)[0]
                    add_unique_name(renamed_item, node_dict)
                    return renamed_item
            raise RuntimeError, "Too many duplicate names"
    

    要在特定节点类型上使用它,您只需在调用apply_convention()时提供正确的名称。这会将场景中的所有关节(天真!)重命名为'jnt_X',同时保持后缀唯一。你会做比这更聪明的事情,就像你的原始代码那样 - 这只是确保叶子是唯一的:

    joint_names=  get_unique_scene_names('joint')               
    
    existing = cmds.ls( type='joint', l = True)
    existing .sort()
    existing .reverse()
    # do this to make sure it works from leaves backwards!
    
    for item in existing :
        apply_convention(item,  'jnt_', joint_names)
    
    # check the uniqueness constraint by looking for how many items share a short name in the dict:
    for d in joint_names:
        print d, len (joint_names[d])
    

    但是,就像我说的那样,计划那些该死的数字后缀,maya一直让他们没有征得许可,所以你不能打击他们:(

答案 1 :(得分:0)

不是为每个ls运行name,而是应该运行一次并将结果存储到set(无序列表 - 稍快一点)。然后在运行check_scene

时进行检查
def check_scene(self, name):
    """Checks entire scene for same name. If duplicate exists,

    Keyword Arguments:
    name -- (string) name of object to be checked
    """

    if not hasattr(self, 'scene'):
        self.scene = set(ls())

    if name not in self.scene:
        return name
    else:
        return ''