DataTree to List of Lists (dynamic depth) c#

script
unhandled

(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?

Cheers,

Merijn


(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:
{0;0}
{0;0;0;1}
{1;0;0}

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 https://stackoverflow.com/a/32685719/2419030 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
        else:
            values.append(val)
    if values:
        tree.AddRange(values, GH_Path(Array[int](indices)))

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

@merijndeleur
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:
tree2nest2tree.gh (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).