SOLVED BaseContainer Sort broken?

I noticed a weird behvaior on a BC's Sort method. See below.

import c4d


if __name__=='__main__':
    items = {0: "a", 1: "b", 2: "c", 3:"d"}
    bc = c4d.BaseContainer()
    
    for x in items.items():
        bc.SetString(x[0], x[1])
    
    bc.Sort()
    for x in bc:
        print (x)
        

This prints out the wrong order:

(1, 'b')
(0, 'a')
(2, 'c')
(3, 'd')

Smells like a bug?

Hi @mp5gosu,

thank you for reaching out to us and thank you for pointing out this behaviour. However, this is not a bug, but an intentional feature which is linked to the fact the sub-menu titles will be stored under the ID 1 in a BaseContainer. Because of that the method will not be fixed and it is also very unlikely that we will update the documentation, as explaining the reason for this behaviour would require revealing more of the non-public API than we are currently comfortable with.

However, since this is an intentional behaviour, you can rely on the fact that this will only happen with the ID 1. I.e., when you place your BaseContainer IDs in the range [1, +MAX_INT32], the sort method should work like intended.

Thank you for your understanding,
Ferdinand

Okay, thanks for the explanation.
Although it makes sense in this particular context, I see a problem there regarding the general purpose of BaseContainers, since they are widely used.

Would it be possible for future API updates to at least provide an optional parameter that the sorting will be in logical order?
Like bc.Sort(natural_range=True) or something like that?

Hi @mp5gosu,

I can ask, but I doubt that this will added, because it is ultimately something that can be "fixed" relatively easily from the user side (see end of posting for example). The only meaningful explanation I can give is that BaseContainer.Sort was implemented for a very specific reason. BaseContainer is not really meant to be a replacement for a sortable collection data type.

Cheers,
Ferdinand

"""A little workaround for the somewhat odd BaseContainer sorting behavior.
"""

import c4d

def cleanSort(bc):
    """A little helper for BaseContainer.Sort().
    """
    # Sort the container.
    bc.Sort()
    # Get out when the IDs 0 and 1 are not of type string.
    if (bc.GetType(0) != c4d.DA_STRING or
        bc.GetType(1) != c4d.DA_STRING):
        return bc
    # Save the value of ID 1
    valIdOne = bc[1]
    # Remove the ID 1 and reinsert it in the "right" place.
    if bc.GetIndexId(0) == 1 and bc.RemoveIndex(0):
        bc.InsDataAfter(1, valIdOne, bc.GetDataPointer(0))
    return bc

def main():
    """
    """
    data = {3: "d", 1: "b", 2: "c", 0:"a"}
    bc = c4d.BaseContainer()
    for eid, value in data.items():
        bc.SetString(eid, value)

    print ("Before:")
    for eid, value in bc:
        print(f"id: {eid}, value:{value}")
    print ("")

    bc = cleanSort(bc)

    print ("After:")
    for eid, value in bc:
        print(f"id: {eid}, value:{value}")


if __name__=='__main__':
    main()

Hehehe, thanks ferdinand.
Really appreciate your effort.
But in this case, I'll go for the 1st based indexing. Not a big deal.

Thanks again! 🙂

Hi @mp5gosu,

I am sorry to inform you that we talked about the issue, implementing an overloaded version of BaseContainer::Sort, and decided that this is not something we want to do in the near future and probably also not at all.

Cheers,
Ferdinand

That's okay, since it is a minor issue.
For newcomers however, there should be a hint in the docs, because it clearly states Sorts the container entries by ID. which is not the case.