DataTree to List of Lists (dynamic depth) c#


(Merijn) #1

Hi all,

I’ve been struggling for a while now to get my grasshopper dataTree to a list of lists in Grasshopper.
The reason I want to do this is to be able to serialise my tree to a Json-file with the correct depth, to eventually be able to recreate the correct data structure again (also within other software).

So, what I want to achieve:

From:                    To: 
{0;0;0}[...]                  [                                  <= Entire Tree
{0;0;1}[...]                      [                              <= {0;*;*}
{0;1;0}[...]                          [                          <= {0;0;*}
{0;1;1}[...]                              [ [...] ],             <= {0;0;0}
{1;0;0}[...]                              [ [...] ]              <= {0;0;1}
                                     [                           <= {0;1;*}
                                          [ [...] ],             <= {0;1;0}
                                          [ [...] ]              <= {0;1;1}
                                 [                               <= {1;*;*}
                                     [                           <= {1;0;*}
                                          [ [...] ]              <= {1;0;0}

I hope that makes any sense…
The problem for me lies in the fact that the depth of the nesting of the lists is dynamic.

Doe anyone have an idea?



(Pfotiad0) #2

I’m not at home (where the freaky stuff exists) right now. Unless some other good C# Samaritan provides a solution I’ll post later a C# that does that.

(Merijn) #3

Great, thanks!

(Pfotiad0) #4

BTW: by that you mean that you have variabe dimension(s) paths?

(Merijn) #5

I mean that I would like to be able to interpret any form/structure a tree can occur in.
For instance:

I would also like to be able to convert that to a list of lists with the correct amount of nesting. However, I would be happy if I would be able to do it with the same dimensions in all the paths, as long as that dimension itself can be varied in.

(qythium) #6

I have a little utility function in Python that does that:

[Buggy code redacted!]
see updated post below

It involves the built in itertools library and a bit of recursion, so that might be tricky to translate into C# directly…
There’s also a json module in Python that lets you do:

import json
json.dump(nested_list, file_name)

(Merijn) #7

Thanks, but this is indeed the problem. Since c# can’t adjust types as easily as python can, I find the problem in the decleration in the List<T>, List<List<T> or even List<List<List<T>>>

P.S. Your python script does exactly what I need, now to get it into a C# component :wink:

(Nathan 'jesterKing' Letwory) #8

You’ll have to use nested lists of the form List<object>, where then items can be anything. See for instance for some ideas.

You’ll have to see more effort when iterating through your data of such a list to figure out the types, but it is doable (the C# 7.0 pattern matching in switch cases is really neat for that, but if(somevar is float f)... else if(somevar is List<object> oblist)... works fine too)

(qythium) #9

Hmm… any reason you can’t use the Python script directly? :laughing:
Since I assume you’re dealing with scripting components and can just pipe data from one to the other.

Also subsequent JSON serialising is much easier than in C# from previous experience - literally all you have to do is call one function: json.dump(obj, filename)

But if you really need to, List<object> should work as pointed out, and I think LINQ in C# has a equivalent GroupBy method - might have a go at it later.

(Tom) #10

I think you misinterpret data trees?! In my understanding its similar to a dictionary with a list as value and the path as a key. Every time you go deeper in the tree structure you just modify the paths, but technically its two dimensional only.

(Merijn) #11

Right, that is indeed how I see it as well, however, I would like to be able to communicate with dynamo. Dynamo works with classic arrays/nested arrays. This is why I would like to convert the data tree.

(Tom) #12

I remember reading about nested lists that creating them is very bad coding style. You could create a graph object having nodes, where each node contains a list of t then. This is how I would do it, however I don’t know much about dynamo…

(qythium) #13

That really depends on the problem and domain, for serialization / data transfer purposes it’s probably not an issue.
Originally I wrote this in order to transfer some four-dimensional data (2D bitmap * RGB values * time) to and from an external Python notebook where it was further processed into a Numpy array.

Here’s the complementary function which turns nested lists into a data tree:

from Grasshopper import DataTree
from Grasshopper.Kernel.Data import GH_Path
from System import Array

def unnest(tree, data, indices=(0,)):
    index = 0
    values = []
    for val in data:
        if hasattr(val, "__iter__") and not isinstance(val, basestring): 
            unnest(tree, val, indices+(index,))
            index += 1
    if values:
        tree.AddRange(values, GH_Path(Array[int](indices)))

tree = DataTree[object]()
unnest(tree, nested_list)

I don’t know anything about Dynamo either, but doesn’t it use IronPython too? Just json.dump() on one end, json.load() on the other and you’re all set to go :slight_smile:

(qythium) #14

Huh, looks like I reinvented the wheel back then :open_mouth:

(Tom) #15

…well in terms of C#, I should have said. Sure there are situation to break these rules. This is an example when a dynamically typed language like Python having a clear advantage.
In C# a generic list of list is already very unreadable piece of code in my opinion. This is why you don’t see it that much. I also believe that C# in general is not the best language to deal with multidimensional generic data. Functional or semi-functional languages are probably stronger here. The whole topic about datastructures in general is a very underestimated problem. … On the other hand IronPython is written in C#, so what works in Python has to work in C# as well.

(qythium) #16

I think there are certain Pythoney things like dynamic class/ function definitions that are hard or impossible to do in a compiled language like C#, but you’re right that they eventually end up on the same CLR runtime.

And yeah, C# generics can be pretty gnarly… I was looking up GroupBy and got a headache sifting through this list of overloads :dizzy_face:

(Merijn) #17

Exactly my thought… :sob:

Would be awesome if you could post it!

(Pfotiad0) #18

LMCQC (Last Minute Code Quality Control) discovered some stupid things. I’ll reform the C# this w/e (but what about the MotoGP in Jerez? you tell me).

(qythium) #19

Here’s a quick demo with the python code above, while we’re waiting for the freaky stuff from Peter :slight_smile: (13.5 KB)

(Still don’t quite understand the insistence on C# for this application - as TomTom pointed out, using nested generic lists is a definite code smell, and having to upcast to List<object> to support arbitrary depth means trouble when further processing. )

(Pfotiad0) #20

In the mean time (adding 3 out options: Lists, Jagged Arrays, Dictionary) here’s the puzzle of the century:

Assume that you get a “snapshot” of a tree (any freaky tree) in a jagged array of type object[][] where rows are the branches and the content (child arrays) is variable (jagged) in Length (kinda a tree). You can store the path at pos 0 as well (for doing the inverse) etc etc. Does this make any sense? (Only In the name of the science I guess).

So we are talking 2 C# things here (tree > jagged , jagged > tree).

All well … except when you attempt to output the thing: GH yields a List of object[] arrays instead of a single object[][] thingy.

Any light bulb ???

BTW: Giulio’s P thingy doesn’t work with freaky trees with random N of dimensions per path (as is the norm in … er … freaky things).