Sort By Volume Python

i search to sort a polysurface list by their volume.
i know with Vbscript, but I would like to know if it’s simplier with python…
maybe i can make a tupple, with first the polysurface, and second the volume. and i sort the tupple with the second column…

Hi,

You can take a list of id’s and sort them in python with a lambda as the key to sort by:

ids.sort(key = lambda id : rs.SurfaceVolume(id)[0])

below in an example script with printouts for checking:

import rhinoscriptsyntax as rs



def sort_by_volume(ids):
    
    
    #test for checking
    print 'NOT SORTED :'
    for id in ids: print rs.SurfaceVolume(id)
    
    ids.sort(key = lambda id : rs.SurfaceVolume(id)[0])
    
    
    #test for checking if now sorted
    print 'SORTED :'
    for id in ids: print rs.SurfaceVolume(id)
    
    return ids
    

ids = rs.GetObjects('select objects to sort by volume')

sorted_ids = sort_by_volume(ids)

Does this make sense?
-Willem

2 Likes

in French We say:
“c’est un truc de ouf!!!”

in fact sort is a method of list, that’s it?

1 Like

Oui c’est ca:

https://www.w3schools.com/python/python_ref_list.asp

Note that here you are sorting the original list and assigning a new name to it as well. It would be better to use return sorted(ids, key =...) to return a new sorted list and avoid this side effect.

Je vous en prie :sunglasses:

1 Like

There is another method to sort objects by a numerical value that does not involve using a lambda function. It relies on the fact that python sorts a list of lists or tuples by the first element in each sub-list.

So you can for example create a nested list of each object’s volume (as index 0) plus its guid (as index1). When you sort the list, the volume numbers will sort, bringing the guids with them synchronously. All you need to do then is unpack the nested list and the guids will be sorted in order of the object volumes.

It’s too late here to create a nice example, but I’ll put one up tomorrow.

1 Like

I thought I had read something like that

import rhinoscriptsyntax as rs

def SortByVolume(objs):
    #create nested list of tuples (volume,object id) and sort
    sort_by_vol=sorted([(rs.SurfaceVolume(obj)[0],obj) for obj in objs])
    #return only the object IDs now sorted in ascending order by volume
    return [item[1] for item in sort_by_vol]
    
objs=rs.GetObjects("Select objects",8,preselect=True)
if objs:
    sorted_objs=SortByVolume(objs)
    #highlight objects in ascending volume order
    rs.UnselectAllObjects()
    for obj in sorted_objs:
        rs.SelectObject(obj)
        rs.Sleep(500)
        rs.UnselectObject(obj)

Try it on this file…
25Ellipsoids.3dm (5.7 MB)

what does this mean?
excuse, it return the second column of tuple in a list… that it’s?

Yes it uses a list comprehension to generate a new list containing the second item from each element of the existing list. It returns this new list.

List comprehensions are great!

Yes, a Graham said, that is a list comprehension. It’s one of the coolest tools in python. In the definition there are two, one for creating the original list of tuples, and the second for extracting the second element of each item (the GUID) from the sorted list of tuples into a new list.

To be honest, the first one is a bit of a risky shortcut - not because of the list comprehension itself, but because, depending on the object, rs.SurfaceVolume might fail. Since I directly asked it for the first element in the return (the volume), if it returns None (fail), the entire script will error out.

So in this case it might be more prudent to have a discrete for loop and fill an empty list as usual one-by-one - checking to see that a volume is actually found for each item. Then you would have to decide what to do if an object fails to return a volume - skip it and continue, or stop the script and tell the user there is a problem…

Ok, but in my case it’s for simple polysurfaces… For a BOM of tubes… I want to start the list by the longer, so by the bigger…

To reverse sort a list (biggest first), you can add the “reverse” argument to sort() or sorted().

sort_by_vol=sorted([(rs.SurfaceVolume(obj)[0],obj) for obj in objs], reverse=True)