1

I'm coming up with a rather trivial problem, but since I'm quite new to python, I'm smashing my head to my desk for a while. (Hurts). Though I believe that's more a logical thing to solve... First I have to say that I'm using the Python SDK for Cinema 4D so I had to change the following code a bit. But here is what I was trying to do and struggling with: I'm trying to group some polygon selections, which are dynamically generated (based on some rules, not that important). Here's how it works the mathematical way: Those selections are based on islands (means, that there are several polygons connected). Then, those selections have to be grouped and put into a list that I can work with. Any polygon has its own index, so this one should be rather simple, but like I said before, I'm quite struggling there.

The main problem is easy to explain: I'm trying to access a non existent index in the first loop, resulting in an index out of range error. I tried evaluating the validity first, but no luck. For those who are familiar with Cinema 4D + Python, I will provide some of the original code if anybody wants that. So far, so bad. Here's the simplified and adapted code.

edit: Forgot to mention that the check which causes the error actually should only check for duplicates, so the current selected number will be skipped since it hal already been processed. This is necessary due to computing-heavy calculations.

Really hope, anybody can bump me in the right direction and this code makes sense so far. :)

def myFunc():

        sel = [0,1,5,12] # changes with every call of "myFunc", for example to [2,8,4,10,9,1], etc. - list alway differs in count of elements, can even be empty, groups are beeing built from these values
        all = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15] # the whole set
        groups = [] # list to store indices-lists into
        indices = [] # list to store selected indices
        count = 0 # number of groups
        tmp = [] # temporary list to copy the indices list into before resetting

        for i in range(len(all)): # loop through values
            if i not in groups[count]: # that's the problematic one; this one actually should check whether "i" is already inside of any list inside the group list, error is simply that I'm trying to check a non existent value
                for index, selected in enumerate(sel): # loop through "sel" and return actual indices. "selected" determines, if "index" is selected. boolean.
                    if not selected: continue # pretty much self-explanatory
                    indices.append(index) # push selected indices to the list
                tmp = indices[:] # clone list
                groups.append(tmp) # push the previous generated list to another list to store groups into
                indices = [] # empty/reset indices-list
                count += 1 # increment count
        print groups    # debug
myFunc()

edit:

After adding a second list which will be filled by extend, not append that acts as counter, everything worked as expected! The list will be a basic list, pretty simple ;)

Robert H.
  • 27
  • 9
  • I can't figure out what you're trying to do from your description, but the list created in the for loop doesn't depend on i at all, so you will get the same "inner" list over and over (13x with the data you show). – bj0 Nov 12 '13 at 23:21
  • 1
    This code is extremely puzzling and I suggest you might get some more useful pointers if you can post a clearer explanation of what you're trying to do. Otherwise you may be looking for solutions for the wrong problems... – Stuart Nov 12 '13 at 23:31
  • Yes. sorry for being so cryptic. Hard to express myself in english. I added a picture: http://bit.ly/1a2zRWV The script should determine those groups and while running through the indices, check if the current index is already exisiting in a group or not. If so, move over to the next index. Hope, this was a bit more helpful. – Robert H. Nov 13 '13 at 00:33

3 Answers3

2
groups[count]

When you first call this, groups is an empty list and count is 0. You can't access the thing at spot 0 in groups, because there is nothing there!

Try making groups = [] to groups = [[]] (i.e. instead of an empty list, a list of lists that only has an empty list).

hankd
  • 649
  • 3
  • 12
  • Yes! That was the initial problem. Your solution not only solved my problem, it actually saves me some lines of code. Thank you very much Hank! – Robert H. Nov 12 '13 at 23:07
1

I'm not sure why you'd want to add the empty list to groups. Perhaps this is better

if i not in groups[count]:

to

if not groups or i not in groups[count]:

You also don't need to copy the list if you're not going to use it for anything else. So you can replace

            tmp = indices[:] # clone list
            groups.append(tmp) # push the previous generated list to another list to store groups into
            indices = [] # empty/reset indices-list

with

            groups.append(indices) # push the previous generated list to another list to store groups into
            indices = [] # empty/reset indices-list

You may even be able to drop count altogether (you can always use len(groups)). You can also replace the inner loop with a listcomprehension

def myFunc():

    sel = [0,1,5,12] # changes with every call of "myFunc", for example to [2,8,4,10,9,1], etc. - list alway differs in count of elements, can even be empty, groups are beeing built from these values
    all = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15] # the whole set
    groups = [] # list to store indices-lists into

    for i in range(len(all)): # loop through values
        if not groups or i not in groups[-1]: # look in the latest group
            indices = [idx for idx, selected in enumerate(sel) if selected]
            groups.append(indices) # push the previous generated list to another list to store groups into
    print groups    # debug
John La Rooy
  • 295,403
  • 53
  • 369
  • 502
  • I believe this would be a problem since "count" would never be incremented therefore it will always be 0. – Robert H. Nov 12 '13 at 23:17
  • @RobertH., good point. So the initial logic was slightly wrong. I'm just refactoring it a bit now – John La Rooy Nov 12 '13 at 23:20
  • Ah, just seen your edit. I had my code like this before, but when appending the list like this, it gave me wrong results. (Afair, lists are beeing referenced, not copied?) The list is still "alive" in the the groups-list, so any change to it would even change any referenced values? Or does python handle this on another way when appending lists? I will definitely dig deeper into that! - Thank you for your input! – Robert H. Nov 12 '13 at 23:22
  • @RobertH. you are rebinding `indices` when you say `indices = []` so at that point it's decoupled from it's previous value. If you were using `indices[:] = []` you would have a problem because now you've also wiped out the contents of the list you appended to groups – John La Rooy Nov 12 '13 at 23:24
  • @RobertH. when you do `indices = []`, it creates a new list and re-assigns the label "indices" to the new list. If "indices" was pointed at a previous list, that list loses that reference. – bj0 Nov 12 '13 at 23:25
  • @RobertH., try the version at the end of my answer. I believe it'll handle the case where groups is empty ok now. – John La Rooy Nov 12 '13 at 23:26
  • @gnibbler works like a charm. For some reson, I'm still getting duplicate entries but I guess this is simply caused by how Py4D selects lists. :) And to all: Thanks for your help, especially for pointing out the decoupling mechanism when resetting lists. – Robert H. Nov 12 '13 at 23:52
  • @RobertH. what is the output _supposed_ to be for those sample inputs? – John La Rooy Nov 12 '13 at 23:59
  • @gnibbler: I took some random numbers, so hard to tell. :D And since I did provide only the values of one "sel" list, it will be difficult to explain. If you consider the second list in the comment (Line 3), those values get counterchecked to the current "sel"-list for duplicates. And if found, it skips the group-creation for the curren value. edit: Sorry for my english, words are hard to find. It actually does the following: Run through every index (int) from "all", expand selection(size depends), put to group. Index is considered for finding dups. – Robert H. Nov 13 '13 at 00:11
  • Pictures say more than thousand words - preparing an image to visualize it better ;) – Robert H. Nov 13 '13 at 00:18
  • @gnibbler: solved it! `if not groups or i not in groups[-1]:` changed to `if not groups or i not in groups[0]:` - since 0 is actually the latest group. -1 is the last group then? I'm kinda confused - an explanation would be nice! – Robert H. Nov 13 '13 at 00:41
  • For some strange reason, I keep getting a duplicate when reaching index 1 (or leaving 0). The duplicate will be appended last. – Robert H. Nov 13 '13 at 00:54
  • @RobertH., You should get some testcases together (inputs with known correct outputs) and post a new question – John La Rooy Nov 13 '13 at 01:03
  • Okay, I'll consider doing so. Though, you helped me alot rethinking my approach and I believe, I can figure this one out myself. I still believe it is something really trivial. :) – Robert H. Nov 13 '13 at 01:19
0

correct line 11 from:

   if i not in groups[count]

to:

   if i not in groups:
kiasy
  • 304
  • 3
  • 6
  • 17
  • `groups` holds lists, and `i` is an integer. This is always going to be `True` then.. – Martijn Pieters Nov 12 '13 at 22:51
  • Hi. Thanks for your answer. Already tried that. This won't help since it then compares to another list (remember, lists in a list). So I have to go deeper one level, or am I missing something? – Robert H. Nov 12 '13 at 22:51
  • What you can do is add something like abc = 0 at the beginning and then once something is added to the list make abc = 1 and make the loop work once abc = 1 (once the list isn't empty anymore). In that loop you can use your original code. – kiasy Nov 12 '13 at 22:54