Page MenuHome

UI List: Custom filter_items() sorting gives unpredictable item order
Closed, ArchivedPublic

Description

System Information
Windows 7

Blender Version
Broken: 2.70

Short description of error
If the custom sorting list flt_neworder are given ints for the desired order, it seems to do something weird:

I expect [::-1] to reverse the order, but instead, it is shifted. [0,1,2,3] and [3,2,1,0] do work as expected however.

Am I completely misunderstanding how this works?

Event Timeline

codemanx assigned this task to Bastien Montagne (mont29).
codemanx raised the priority of this task from to 90.
codemanx updated the task description. (Show Details)
codemanx edited a custom field.
codemanx added a subscriber: codemanx.

I figured out how to sort properly, but is it really intended to work like that?

flt_neworder = [x[1] for x in sorted(
        zip(
            [x[0] for x in sorted(enumerate(col), key=lambda x: x[1].label)],
            range(len(col))
        )
    )
]

I need to sort the enumerated items, zip the indices with a range() and sort by the indices, then use the re-arranged numbers of range()...

Bastien Montagne (mont29) lowered the priority of this task from 90 to 30.Apr 23 2014, 3:41 PM

Could you pleas attach a simple script showing the issue? Also, could you try list([1, 0, 2, 3][::-1])?

flt_neworder = list([1, 0, 2, 3][::-1])

gives D, A, C, B and without [::-1] it is C, B, D, A.

list() makes no difference.

Example script:

Bastien Montagne (mont29) changed the task status from Unknown Status to Archived.Apr 23 2014, 7:52 PM

Uh… ok, so this is just misunderstanding of how flt_neworder list works.
[1, 0, 2, 3] means "elem1 will be second, elem2 will be first, elem3 will be third, elem4 will be forth"
reversed, [3, 2 ,0, 1] means "elem1 will be forth, elem2 will be third, elem3 will be first, elem4 will be second"

It’s a mapping, position in the list is index of element in collection, value of this list index is position of the element in UIList.

Not a bug, closing. :)

Ok, I see. It would be a lot simpler if the list position was the new index and the int value the original index.

Found another way btw, but relies on the fact that dicts are sorted in CPython afaik:

import operator

if self.use_filter_sort_alpha:
    flt_neworder = tuple({k: i for i, (k, v) in enumerate(sorted(enumerate(item.label for item in col), key=operator.itemgetter(1)))}.values())

No, dicts are not sorted in CPython… You should rather consider using OrderedDict (collections module). ;)

Also, what kind of sorting are you trying to do exactly?

Alphabetically by a StringProperty() in a CollectionProperty()'s PropertyGroup.

The above code turns out to be the fastest solution for large collections:

http://stackoverflow.com/questions/23256318/order-mapping-more-efficient-python-solution-for-sorting

You're right on the dicts, they print in unpredictable order as it seems. But the code gives proper results, so works fine and should be implementation independent.