dissidia
dissidia

Reputation: 1581

Having problems in extracting duplicates

I am stumped with this problem, and no matter how I get around it, it is still giving me the same result.

Basically, supposedly I have 2 groups - GrpA_null and GrpB_null, each having 2 meshes in them and are named exactly the same, brick_geo and bars_geo - Result: GrpA_null --> brick_geo, bars_geo

But for some reason, in the code below which I presume is the one giving me problems, when it is run, the program states that GrpA_null has the same duplicates as GrpB_null, probably they are referencing the brick_geo and bars_geo. As soon as the code is run, my children geo have a numerical value behind, - Result: GrpA_null --> brick_geo0, bars_geo0, GrpB_null1 --> brick_geo, bars_geo1

And so, I tried to modify the code such that it will as long as the Parent (GrpA_null and GrpB_null) is different, it shall not 'touch' on the children.

Could someone kindly advice me on it?

    def extractDuplicateBoxList(self, inputs):
    result = {}

    for i in range(0, len(inputs)):
        print '<<< i is : %s' %i
        for n in range(0, len(inputs)):
            print '<<< n is %s' %n
            if i != n:
                name = inputs[i].getShortName()
                # Result: brick_geo

                Lname = inputs[i].getLongName()
                # Result: |GrpA_null|concrete_geo

                if name == inputs[n].getShortName():
                    # If list already created as result.
                    if result.has_key(name):
                        # Make sure its not already in the list and add it.
                        alreadyAdded = False
                        for box in result[name]:
                            if box == inputs[i]:
                                alreadyAdded = True
                        if alreadyAdded == False:
                            result[name].append(inputs[i])
                    # Otherwise create a new list and add it.
                    else:
                        result[name] = []
                        result[name].append(inputs[i])

    return result

Upvotes: 1

Views: 77

Answers (3)

theodox
theodox

Reputation: 12218

this may be do what your looking for if I understand it, which seems to be comparing the sub-hierarchies of different nodes to see if they are they have the same names.

import maya.cmds as cmds

def child_nodes(node):
    ''' returns a set with the relative paths of all <node>'s children'''
    root = cmds.ls(node, l=True)[0]
    children = cmds.listRelatives(node, ad=True, f=True)
    return set( [k[len(root):] for k in children])

child_nodes('group1')
# Result: set([u'|pCube1|pCubeShape1', u'|pSphere1', u'|pSphere1|pSphereShape1', u'|pCube1']) # 

# note the returns are NOT valid maya paths, since i've removed the root <node>, 
# you'd need to add it back in to actually access a real shape here:

all_kids = child_nodes('group1')
real_children  = ['group1' + n for n in all_kids ] 

Since the returns are sets, you can test to see if they are equal, see if one is a subset or superset of the other, see what they have in common and so on:

# compare children
child_nodes('group1') == child_nodes('group2')

#one is subset:
child_nodes('group1').issuperset(child_nodes('group2'))

Iterating over a bunch of nodes is easy:

# collect all the child sets of a bunch of nodes:
kids =   dict ( (k, child_nodes(k)) for k in ls(*nodes)) 

Upvotes: 0

bitsplit
bitsplit

Reputation: 1060

There are a couple of things you may want to be aware of. First and foremost, indentation matters in Python. I don't know if the indentation of your code as is is as intended, but your function code should be indented further in than your function def.

Secondly, I find your question a little difficult to understand. But there are several things which would improve your code.

In the collections module, there is (or should be) a type called defaultdict. This type is similar to a dict, except for it having a default value of the type you specify. So a defaultdict(int) will have a default of 0 when you get a key, even if the key wasn't there before. This allows the implementation of counters, such as to find duplicates without sorting.

from collections import defaultdict

counter = defaultdict(int)

for item in items:
    counter[item] += 1

This brings me to another point. Python for loops implement a for-each structure. You almost never need to enumerate your items in order to then access them. So, instead of

for i in range(0,len(inputs)):

you want to use

for input in inputs:

and if you really need to enumerate your inputs

for i,input in enumerate(inputs):

Finally, you can iterate and filter through iterable objects using list comprehensions, dict comprehensions, or generator expressions. They are very powerful. See Create a dictionary with list comprehension in Python

Try this code out, play with it. See if it works for you.

from collections import defaultdict

def extractDuplicateBoxList(self, inputs):
    counts = defaultdict(int)

    for input in inputs:
        counts[input.getShortName()] += 1
    dup_shns = set([k for k,v in counts.items() if v > 1])
    dups = [i for i in inputs if input.getShortName() in dup_shns]

    return dups

Upvotes: 1

eyquem
eyquem

Reputation: 27585

I was on the point to write the same remarks as bitsplit, he has already done it.

So I just give you for the moment a code that I think is doing exactly the same as yours, based on these remarks and the use of the get dictionary's method:

from collections import defaultdict

def extract_Duplicate_BoxList(self, inputs):
    result = defaultdict()

    for i,A in enumerate(inputs):
        print '<<< i is : %s' %i
        name  = A.getShortName() # Result: brick_geo
        Lname = A.getLongName()  # Result: |GrpA_null|concrete_geo

        for n in (j for j,B in enumerate(inputs)
                  if j!=i and B.getShortName()==name):
            print '<<< n is %s' %n
            if A not in result.get(name,[])):
                result[name].append(A)

    return result

.

Secondly, as bitsplit said it, I find your question ununderstandable.
Could you give more information on the elements of inputs ?
Your explanations about GrpA_null and GrpB_null and the names and the meshes are unclear.

.

EDIT:
If my reduction/simplification is correct, examining it , I see that What you essentially does is to compare A and B elements of inputs (with A!=B) and you record A in the dictionary result at key shortname (only one time) if A and B have the same shortname shortname;
I think this code can still be reduced to just:

def extract_Duplicate_BoxList(inputs):
    result = defaultdict()

    for i,A in enumerate(inputs):
        print '<<< i is : %s' %i
        result[B.getShortName()].append(A)

    return result

Upvotes: 0

Related Questions