List.Rank in Python

looks like DSCore doesn’t have List.Rank() method, how to get the maximum nested list level in Python

hello


cordially
christian.stan

1 Like

thanks christian, Python code is needed instead of DesignScript code

1 Like

Can you post a simple, reproducible case?

1 Like

import sys
import clr

clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

a=IN[0]
b=repr(a)
c=b.count("[")
OUT = c

following form of list data this way may be obsolete
cordially
christian.stan

import clr
clr.AddReference(‘DSCoreNodes’)
from DSCore import *

lst = [[1], [[2], [3]], [4]]

#OUT = List.Transpose(lst) # works OK
OUT = List.Rank(lst) # doesn’t work

image

You’ve defined a Dynamo list, not a Python one. They are called the same thing, but they aren’t. To make things more difficult for you, a List object from Dynamo will automatically be converted to a Python list which will outperform the Dynamo list as it’s native, just like moving a Python list between Dynamo nodes without converting it to a Dynamo list would slow things down there.

Once you make a valid Dynamo list, you can work with the list tools quite readily, but other Pythonic tools may not work.

To access the Rank property it’s actually easier to add the ProtoCore library to the CLR, import that library as an alias like PRT, and utilize the ‘Utils class and call the GetMaxRankForArray method.

thanks JacobSmall for the insight, seems i have trouble to find GetMaxRankForArray method, see below code FYI:
import clr
#clr.AddReference(‘DSCoreNodes’)
#from DSCore import *
clr.AddReference(‘ProtoCore’)
import ProtoCore as PRT

lst = [[1], [[2], [3]], [4]]

#OUT = List.Transpose(lst) # works OK
#OUT = List.Rank(lst) # doesn’t work
OUT = PRT.Utils.ArrayUtils.GetMaxRankForArray(lst)

Your list is still a Python list. Need to build a Dynamo one directly, which is not easily done. Everything you input will be converted to a Python list. Everything that makes a list will be converted to a Python list.

Basically, I can’t think of a situation where this is a good idea…

Why do you need it?

right, i’ll directly use List.Rank node as another input to Python node, thanks again.

This Python based method should do the trick in both CPython 3 and IronPython 2 engines:

def GetDepth(lst): #define the fuction
    if not isinstance(lst, list): return 0 #if the input list isn't a list, return 0
    depth = 1 #set the depth to 1
    for obj in lst: #for each object in the list
        if isinstance(obj, list): #is the object a list
            d = 1 + GetDepth(obj) #set the variable d to one plus the result of GetDepth on the list to the list (calling the function within itself)
            depth = max(depth, d) #set depth to the maximum of D and depth
    return depth #return the depth

lst = [1, [2], [[3]], [[[4]]], [[[[5]]]]] #a list of lists and objects to test

OUT = GetDepth(lst), [GetDepth(l) for l in lst] #testing the definition and returning it to the Dynamo environment

and a simplification that’s hardter to annotate:

def depth(L): return isinstance(L, list) and max(map(depth, L))+1

lst = [1, [2],[[3]],[[[4]]],[[[[5]]]]]

OUT = depth(lst)
1 Like

Another python solution, flattening nested lists or collections (for each level)

import sys
import clr
import System
from System.Collections.Generic import List

def is_collection(x):
    return isinstance(x, list) or \
            (hasattr(x, "GetType") and \
            x.GetType().GetInterface("IEnumerable") is not None)

def get_max_rank(lst):
    rank = 1
    while any(is_collection(j) for j in lst):
        rank += 1
        lst = [list(i) for i in lst if is_collection(i)] # remove items are not list
        lst = sum(lst, []) # flat the list
    return rank
    
OUT = get_max_rank(IN[0])

thanks all, both works great! neat code of jacob.small recursive approach, and performance wise of c.poupin approach for very big list.

1 Like