I have the following scenario for which I've been experiencing performance problems:The context is a level editor of a new engine for an old video game (whose source is unavailable) in Unity. Basically I'm writing a level editor for Unity to shape old data structures into contemporary, more usable ones, i.e. parts/entities instead of a bunch of unrelated models/polygons.Here's a tree of how things are organized in the old game:Container (dozens)Models (hundreds)Polygons (thousands)Here's what I'd like to achieve:Group(s): for grouping related objectsObject(s): a tree, a ship etc ... Part(s): an object's parts with specific material etc ...Depending what the final object looks like on the screen, the initial data (models/polygons) is a mess, where there are merged or unrelated parts in a model and its polygons.Other problems emerge due to this, for instance, what used to be a simple pointer update to update a texture or color is simply not possible from within Unity.Here things I need and what I've done:I need to be able to track implicit and explicit references to models and polygons. This is to ensure that valid objects are built and therefore prevent incorrect content.Basically the user can create a part from either the model or or one of its polygons, the opposite being disallowed depending what's chosen first.Here's a picture with explanations:Scene9 is of type ContainerM123_456_ABC... are of type ModelP123_456_ABC... are of type PolygonA green icon is an explicit referenceA yellow icon is an implicit referenceA red icon is a non-referenced itemAlso, the user interface is augmented by elements getting disabled whenever appropriate to help user picking the right actions when building the level, etc ...Here, the issues I am experiencing:Querying for explicit/implicit references between around 300 models and 7000 polygons becomes slow over time as relationships gets created.I've been using a couple of List<T> and do LINQ queries between them:everythingall modelsall polygonsimplicit modelsimplicit polygonsexplicit modelsexplicit polygonsMinus the spaghetti logic, it does works but it's slow. Then I've upgraded to HashSet<T> with custom Comparer<T> which greatly improved speed but it's still not fast enough. All this results in freezes in the user interface.Main consideration is that within Unity, loops are rather tight, calls at high rate, immediate mode UI and no asynchronous calls features (Mono is roughly .NET 3.5).I am starting to consider that my approach using lists is flawed and was thinking that a better data structure could be used for performant queries.Can you suggest a more appropriate data structure to use for such scenario ?EDITHere is a diagram showing the new approach I'm trying after your suggestions:Notes:IScenePrimitive consists of 3 int and an EnumISceneReference.IsRef is simply IsRefExplicit || IsRefImplicitMissing things here are a dictionary in Scene for quick access to a model/polygon, when user selects something I retrieve these using hashes without having to enumerate, etc ...Interesting parts in code:SceneModel:    public override bool IsRefExplicit    {        get { return _isRefExplicit; }        set        {            _isRefExplicit = value;            if (value)            {                Debug.Assert(_polygons.None(s => s.IsRefExplicit));                foreach (var polygon in _polygons)                    polygon.IsRefImplicit = true;            }            else            {                Debug.Assert(_polygons.All(s => s.IsRefImplicit));                foreach (var polygon in _polygons)                    polygon.IsRefImplicit = false;            }        }    }    public override bool IsRefImplicit    {        get { return _isRefImplicit; }        set        {            _isRefImplicit = value;            if (value)                Debug.Assert(_polygons.Any(s => s.IsRefExplicit));        }    }ScenePolygon:    public override bool IsRefExplicit    {        get { return _isRefExplicit; }        set        {            _isRefExplicit = value;            if (value)            {                Debug.Assert(!Model.IsRefExplicit);                Model.IsRefImplicit = true;            }            else            {                Debug.Assert(Model.IsRefImplicit);                Model.IsRefImplicit = false;            }        }    }    public override bool IsRefImplicit    {        get { return _isRefImplicit; }        set        {            _isRefImplicit = value;            Debug.Assert(Model.IsRefExplicit);        }    }That's all that really happens, LINQ on a dozen items instead of many more (300 models querying each 7000 polygons X). I still have to test it to see how well it performs but it should perform much faster, to be continued.
What's an efficient data structure to make a lot of queries between parents/childs?
c#;data structures;performance;query;unity3d
Let's take a look at SceneModel's IsRefExplicit. I've added comments:SceneModelpublic override bool IsRefExplicit{    get { return _isRefExplicit; }    set    {        _isRefExplicit = value;        if (value)        {            // If the model has an explicit reference            // then all its polygon have an implicit reference            Debug.Assert(_polygons.None(s => s.IsRefExplicit));            foreach (var polygon in _polygons)                polygon.IsRefImplicit = true;        }        else        {            // If the model doesn't have an explicit reference            // then all its polygon don't have an implicit reference            Debug.Assert(_polygons.All(s => s.IsRefImplicit));            foreach (var polygon in _polygons)                polygon.IsRefImplicit = false;        }    }}This can be done by simply changing the implementation of ScenePolygon to query the Model:SceneModelpublic override bool IsRefExplicit{    get { return _isRefExplicit; }    set { _isRefExplicit = value; }}ScenePolygonpublic override bool IsRefImplicit{    get { return Model.IsRefExplicit; }    set { throw new NotSupportedException(); }}No more loop.Of course the above is under tha assumption that IsRefImplicit on ScenePolygon will only be set by SceneModel. If this assumption is not true, then perhaps you shouldn't do polygon.IsRefImplicit = false; on SceneModel because the IsRefImplicit may have been set to true by another code.Now, let's take a look at ScenePolygon's IsRefExplicit:ScenePolygonpublic override bool IsRefExplicit{    get { return _isRefExplicit; }    set    {        _isRefExplicit = value;        if (value)        {            // If the polygon has an explicit reference            // then the model has an implicit reference            Debug.Assert(!Model.IsRefExplicit);            Model.IsRefImplicit = true;        }        else        {            // If the polygon doens't have an explicit reference            // then the model doens't have an implicit reference?            // ...            // Could there be another polygon of the model with an explicit reference?            // If there is, then the model should remain with an implicit reference            Debug.Assert(Model.IsRefImplicit);            Model.IsRefImplicit = false;        }    }}In this case what you need is reference counting. Keep in the SceneModel how many ScenePolygon does it have with IsRefExplicit and let ScenePolygon increment it or decrement it as needed.public override bool IsRefExplicit{    get { return _isRefExplicit; }    set    {        if (_isRefExplicit == value)        {            return;        }        _isRefExplicit = value;        if (value)        {            Model.IncrementImplicitRefCount();        }        else        {            Model.DecrementImplicitRefCount();        }    }}Then the model can implement IsRefImplicit by checking if the current reference count is greater than 0. For abstract, we could write the rules like this:Model.IsRefImplicit = contains at least one polygon with IsRefExplicit.    Have a counter, and check if it is greater than 0.    There is no setter.Model.IsRefExplicit = all the polygons have IsRefImplicit.    Store a bool backing field.Polygon.IsRefImplicit = belongs to an model with IsRefExplicit.    Read Model.IsRefExplicit    There is no setter.Polygon.IsRefExplicit = should mark the model IsRefImplicit.    Store a bool backing field.    The setter will increment the counter of the Model when set to true,                and decrement it when set to false,                do nothing if the value didn't change.Then the concern is to annotate IsRefExplicit and let IsRefImplicit be populated by the code you have. So, you would be reading the source data and looking in some dictionary for the object it references, and annotating it. If the object is not in the dictionary you create it and add it.If you change your code to use Interlocked (use Increment and Decrement for the reference count, and use CompareExchange and Exchange on an int set to 0 or 1 instead of the bool backing fields) then the resulting code will be thread-safe, and you will be able to have multiple threads writing IsRefExplicit.If you change your lists/dictionaries to thread-safe solutions such as ConcurrentDictionary, then the structure can also be populated by multiple threads.