nortikin / sverchok

Sverchok
http://nortikin.github.io/sverchok/
GNU General Public License v3.0
2.26k stars 234 forks source link

natural sorting (object names) #1987

Closed enzyme69 closed 6 years ago

enzyme69 commented 6 years ago

Once again I encountered a situation where Object sorting become an issue because of no padding on the names. Usually after using Viewer BMesh node and then using Objects In node to get the objects back, the list sorting become a bit wrong.

screen shot 2017-12-29 at 9 11 08 pm

So I created a bridge that sort the object by natural sorting.

SN LITE as below:

"""
in obnames s
out obsorted s
"""

# natural sorting for name without zero padding

import re
import bpy

# INPUT: Name of objects to be sorted

#mylist = ['apple_10', 'apple_1', 'apple_12', 'apple_123', 'apple_2']

def natural_sort(l): 
    convert = lambda text: int(text) if text.isdigit() else text.lower() 
    alphanum_key = lambda key: [ convert(c) for c in re.split('([0-9]+)', key) ] 
    return sorted(l, key = alphanum_key)

obnamesorted = natural_sort(obnames)

obsorted = []

for ob in obnamesorted:
    obsorted.append(bpy.data.objects[ob])
enzyme69 commented 6 years ago

As a result the list is back to original sorting.

Object ID Sorting can probably do the job as well with custom index value, but that is for future user to figure out themselves.

screen shot 2017-12-29 at 9 14 05 pm

Basically what I am doing:

enzyme69 commented 6 years ago

Oh yeah btw I tried using Exec Mod Node, but I cannot "import re" for that node. Not sure why. @Kosvor2

zeffii commented 6 years ago

but you already can sort by object's index (using object['idx'] as key ) --- If the objects are generated by a Sverchok Object node (like BMviewer etc...)

in ExecNodeMod. just this one line.

extend(list(sorted(V1, key=lambda obj: obj['idx'])))
zeffii commented 6 years ago
NameError: name 're' is not defined

we can/should fix that. It's a matter of adding locals() to the exec( ) context. Similar to this change

in ExecNodeMod, you can do this too:

def natural_sort(obj):
    import re
    return int(re.search('\d+', obj.name).group())

extend(sorted(V1, key=natural_sort))
zeffii commented 6 years ago

see

https://github.com/nortikin/sverchok/blob/69058d106528a671a74394751b12ed6911dabe1c/nodes/script/multi_exec.py#L192-L199

we can change it to

- exec('\n'.join([j.line for j in self.dynamic_strings])) 
+ exec('\n'.join([j.line for j in self.dynamic_strings]), locals()) 

and imports will work (in main body of the lines of text).

zeffii commented 6 years ago

i've just updated Sverchok. you can now write

from re import search

natural_sort = lambda obj: int(search('\d+', obj.name).group())
extend(sorted(V1, key=natural_sort))

in ExecNode Mod.

nortikin commented 6 years ago

lovely!