I did some more testing on a solution to flatten any list in a CPython node, just as I did in IronPython nodes.
A solution that looks and works just like the native Dynamo flatten node.
- Multiple levels is mandatory
- As fast and reliable as possible
- Option to flatten to a certain amound just like the node
For testing I used a list of 80.000+ items, 10 levels deep and all kinds of Python and Dynamo content.
Dynamo/Revit content might break a nice workflow. So UnwrapElement is sometimes needed.
I found and used nice solutions on stackoverflow
def _flatten(xs,lv=-1,int=1):
def _loop(ys,lv=-1,int=1):
for i in ys:
if isinstance(UnwrapElement(i), list) and (int<=lv or lv<=-1): # slower but more stable
#if isinstance(i, list) and (int<=lv or lv<=-1): #half the time but sometimes less stable result
yield from _flatten(i,lv,int+1)
else:
yield i
res = _loop(xs,lv,int)
return res
And the option with a list instead of a yield works also just fine.
def _flatten(xs,lv=-1,int=1):
res = []
def _loop(ys,lv=-1,int=1):
for i in ys:
if isinstance(UnwrapElement(i), list) and (int<=lv or lv<=-1): # slower but more stable
#if isinstance(i, list) and (int<=lv or lv<=-1): #half the time but sometimes less stable result
_loop(i,lv,int+1)
else:
res.append(i)
_loop(xs,lv,int)
return res
While calling this definition the argument lv is not needed.
Just using flatten(myList) will flatten everything just like flatten(myList,-1) would have done.
The last argument int=1 is just a helper/counter, so the definition will know when to stop.
This is the Dynamo script for more testing and the 8 rough examples. And 3 examples with level option included.
Building and working with long list will take time. I also added a time.sleep to count time. So be a little patient while testing. flatten.dyn (93.0 KB)
While using TuneUp you can also conclude a few other things.
- The flatten node wins all the times. Loading Python and all the libraries simply takes time. Even without the time.sleep(1) the native node seems to be half the excecution time. Nonetheless I’am not really unhappy, because this function seems te be almost as fast as calling the node in an IronPython script -as I used to-
- Unwrapping a complete list in IronPython is logically much faster than checking and unwrapping parts as needed in CPython.
Only Flatten:
Flatten and UnwrapElement:
Only Flatten and without the time.sleep(1)