Find orphaned elements within a hierarchy - c#

I am struggling to find a good solution for this. It's fairly straight forward to find the orphaned elements, but the trouble is storing them in such a way that they can easily be merged back into the hierarchy at a later point.
I the following abstract class that has multiple implementations:
public abstract class FilterElement
{
public abstract string ID { get; }
public abstract IEnumerable<FilterElement> Children { get; set; }
public FilterElement Parent { get; set; }
}
I have two hierarchies of FilterElement - the "master" (i.e. the main structure), and the "filters". The filters point at elements in the master - however, if these master elements do not exist, I wish to create a third structure, the "orphans".
I'm struggling to do this. While it's easy to identify the orphaned elements, I don't know how to store them effectively. This is the current solution:
Note: "GetFlatKey" returns a unique key for the element based on it's parents & children, and "RecursiveSelect" effectively flattens the hierarchy:
private IEnumerable<FilterElement> GetOrphanedFilterElements
(IEnumerable<FilterElement> filters,
IEnumerable<IFilterFileViewModel> visibleList)
{
var flattenedMasterList = visibleList.Cast<IFilterViewModel>()
.RecursiveSelect(f => f.Children)
.Select(x => x.GetFlatKey).ToList();
var orphanedFilterFiles = new List<FilterElement>();
foreach (var f in filters.RecursiveSelect(f => f.Children))
{
// Remove non orphaned files.
if (!flattenedMasterList.Contains(f.GetFlatKey))
{
orphanedFilterFiles.Add((f));
}
}
return orphanedFilterFiles;
}
The problem with this is that the elements in the orphanedFilterFiles list contain references to other elements - e.g. An orphan will have a parent, which may have non-orphaned Children. This makes it difficult to merge back into the final hierarchy, which is the main issue.
Can anyone help me find a better solution, or just tell me what I'm doing wrong?

Related

Logic for creating a tree like representation

I have an requirement to show a binary tree like structure on the web page that will
be used to represent parent-child relation. Unlike binary tree, this tree can have multiple child nodes
and the childs can have further children and this process will continue until no child left of their parent.
So, I am pretty much confused on how should my data-model should be and my thinking is not going beyond this one
public class Parent
{
public string parentName {get;set;} // As their will be one start for this tree, I will have one parent node that will show the parent
public List<string> child {get;set;} // As the parent can have multiple children, I can have a list of string
}
But the question is that the child can also act as parent as they can also have children. How should I
implement such structure.
Thanks
A string can't have child elements of its own, so it's not a good representation.
A simple way is to make the child elements simply a List of the same type of element as the parent. Let's call them all Node instead:
public class Node
{
public string Name { get; set; }
public List<Node> ChildNodes { get; set; }
}

Defensive Code to prevent Infinite Recursion in Parent/Child Hierarchy

Given an Object as Such
public class Thing
{
public Thing() { this.children = new List<Thing>();}
public int Id {get; set;}
public string Name {get; set;}
public List<Thing> children{ get; set;}
public string ToString(int level = 0)
{
//Level is added purely to add a visual hierarchy
var sb = new StringBuilder();
sb.Append(new String('-',level));
sb.AppendLine($"id:{Id} Name:{Name}");
foreach(var child in children)
{
sb.Append(child.ToString(level + 1));
}
return sb.ToString();
}
}
and if used (abused!?) in such a way
public static void Main()
{
var root = new Thing{Id = 1,Name = "Thing1"};
var thing2 = new Thing{Id = 2,Name = "Thing2"};
var thing3 = new Thing{Id = 3,Name = "Thing3"};
root.children.Add(thing2);
thing2.children.Add(thing3);
thing3.children.Add(root); //problem is here
Console.WriteLine(root.ToString());
}
how does one be defensive about this kind of scenario.
This code as it stands produces a stackoverflow, infinite recursion, or memory exceeded error.
In a (IIS) website this was causing the w3 worker processes to crash, and eventually the app pool to shut down (Rapid-Fail Protection)
The code above is indicative only to reproduce the problem. In the actual scenario, the structure is coming from a database with Id and ParentId.
Database table structure similar to
CREATE TABLE Thing(
Id INT NOT NULL PRIMARY KEY,
Name NVARCHAR(255) NOT NULL,
ParentThingId INT NULL //References self
)
The issue is that the creation of the 'things' by users is not preventing a incestuous relationship (i.e. a Parent could have children (who could have children etc.... that one eventually points at the parent again). One could put a constraint on the db to prevent the thing not being its own parent (makes sense), but depending on depth this could get ugly, and there is some argument that a circular reference may be required (we are still debating this....)
So arguably the structures can be circular, but if you want to render this kind of structure on a web page say as a <ul><li><a> tag kind of thing in a parent/child menu, how does one become proactive about dealing with this user generated data issue in code?
.NET fiddle here
One way would be to include a collection of visited nodes in the recursive call. If visited before you are in a cycle.
public string ToString(int level = 0, HashSet<int> visited)
{
foreach(var child in children)
{
if(visited.Add(child.Id))
sb.Append(child.ToString(level + 1, visited));
else
//Handle the case when a cycle is detected.
}
return sb.ToString();
}
You can unfold the tree structure by putting each element on a stack or queue and popping items of there while the collection has items. In the while loop you put the children of each item on the queue.
If you care about the level of the item in the tree you need can use a helper object that stores that.
Edit:
While unfolding the tree you can put each item on a new list and use that as reference for circular problems.
If you can a) eliminate that possibility of wanting to have circular references and b) guarantee that all children are already known of when that parent is created, its a great opportunity to make children an immutable collection that's only set via the constructor.
That gives you a class that, by structural recursion, you know cannot contain any loops, no matter how big the overall structure is. Something like:
public sealed class Thing
{
public Thing(IEnumerable<Thing> children) {
this._children = children.ToList().AsReadOnly();
}
private readonly ReadOnlyCollection<Thing> _children;
public int Id {get; set;}
public string Name {get; set;}
public IEnumerable<Thing> children {
get {
return _children;
}
}
public string ToString(int level = 0)
{
//Level is added purely to add a visual hierarchy
var sb = new StringBuilder();
sb.Append(new String('-',level));
sb.AppendLine($"id:{Id} Name:{Name}");
foreach(var child in children)
{
sb.Append(child.ToString(level + 1));
}
return sb.ToString();
}
}
Now, of course, those conditions I have stated above are quite big "if"s, so you need to consider whether it's a good fit for you.

Removing Tree Branches with C#

I have a List<Leaf> named items in C#. A Leaf has the following properties:
public class Leaf
{
public int ID { get; set; }
public int ParentID { get; set; }
public bool IsFlagged { get; set; }
}
If a Leaf has the IsFlagged property set then I need to remove it from the collection of items. In addition, I need to remove all of that Leaf entity's children. I'm trying to figure out the most elegant way to write this code. Currently, I have a loop within a loop, but it seems sloppy.
Does anyone know of an elegant way to do this?
Perhaps:
void RemoveItAndChildren(Leaf leaf)
{
foreach (Leaf item in items)
if (item.ParentID == leaf.ID)
RemoveItAndChildren(item);
items.Remove(leaf);
}
And use so:
foreach (Leaf leaf in items)
if (leaf.IsFlagged)
RemoveItAndChildren(leaf);
Note that, as in a comment above, something like the following might be more appropriate:
public class Leaf2
{
List<Leaf2> Children;
bool IsFlagged { get; set; }
}
Most reasonable (and probably "the most elegant") way of dealing with tree is to store it as a tree, not an array/list. In this case you'll not need to deal with walking elements to try to find all children.
Note that depending on your actual requirements tree may not be best data structure, but for removing node with all children nodes it would be hard to beat regular tree.

Nested parent child lists where order by doesn't work

I have the following code:
public class Navigation
{
public Navigation()
{
SubNavigation = new List<Navigation>();
}
public int Order { get; set; }
public string Text { get; set; }
public string RouteName { get; set; }
public IList<Navigation> SubNavigation { get; set; }
}
I then have:
IList<Navigation> list = new List<Navigation>();
I populate the list with some data. Not all items have a sub navigation. Currently the navigation only goes one level deep.
Now I would like to sort both the navigation and the sub-navigation for each item by order. I have tried all kinds of approaches but no matter what I tried I could not get the sub-navigation to sort without re-creating the object. The below code works:
IList<Navigation> result = list.OrderBy(l => l.Order)
.Select(n => new Navigation
{
Order = n.Order,
Text = n.Text,
RouteName = n.RouteName,
SubNavigation = n.SubNavigation.OrderBy(s => s.Order).ToList()
}).ToList();
I am not in love with this approach and my question is if there is any cleaner/better way of doing this using LINQ and the method syntax?
You could add a new property on your object:
public IList<Navigation> OrderedSubNavigation
{
get
{
return SubNavigation.OrderBy(s => s.Order).ToList();
}
}
Then when you want the ordered one you just use that.
I have tried all kinds of approaches but no matter what I tried I could not get the sub-navigation to sort without re-creating the object.
Well no, you wouldn't be able to cleanly - because getting the subnavigation to be in a particular order requires modifying the existing object, and LINQ's not built for that. LINQ's built for queries, which shouldn't mutate the data they work on.
One option would be to only sort the subnavigation when you need to - live with the fact that it's unordered within a Navigation, and then when you actually need the subnavigation items (e.g. for display) you can order at that point. Aside from anything else, this will make it more efficient if you end up not displaying the subnavigation items.

Objects containing list of same object type

Is there anything wrong with defining something like this:
class ObjectA
{
property a;
property b;
List <ObjectA> c;
...
}
No, and because the answer needs at least 30 characters, I'll add that this is a common pattern.
Since you included the oop tag, though, I'll add that this pattern gives a lot of control to the outside world. If c is a list of children, for example, you're giving everyone who has access to an instance of ObjectA the ability to add, delete, or replace its children.
A tighter approach would be to use some sort of read-only type (perhaps implementing IList<ObjectA>) to expose the children.
EDIT
Note that the following still allows others to modify your list:
class ObjectA
{
property a;
property b;
List <ObjectA> c;
...
public List<ObjectA> Children { get { return c; } }
}
The absence of a setter only prevents outsiders from replacing the list object.
Nope. That's perfectly acceptable. Tree structures do this.
It is perfectly valid. For example, you would have to do something like this to build a tree data structure (parent node contains a list of child nodes).
i have to ask if your question is about putting a List< > in there, or if it is about putting a List< ObjectA > inside of ObjectA. and the answer to both questions is "Yes"!
the thing to keep in mind is that by default, the access is private. if you want other classes to use this list, then you need to add a few things to your class...
class ObjectA
{
property a;
property b;
List <ObjectA> c;
// allow access, but not assignment
// you can still modify the list from outside, you just cant
// assign a new list from outside the class
public List<ObjectA> somePropertyName{ get { return this.c;}}
// same as above, only allow derived child classes to set the list
public List<ObjectA> somePropertyName{ get { return this.c;}
protected set { this.c = value;} }
// allow all access
public List<ObjectA> somePropertyName{ get { return this.c;}
set { this.c = value;} }
}
No. This is valid. Many structures uses this graph like pattern.
If you eg have a base collection class
namespace MiniGraphLibrary
{
public class GraphCollection
{
public Node Root { set; get; }
public Node FindChild(Node root)
{
throw new NotImplementedException();
}
public Node InsertNode(Node root, Node nodeToBeInserted)
{
throw new NotImplementedException();
}
}
}
Then you can have the node act like this:
namespace MiniGraphLibrary
{
public class Node
{
private string _info;
private List<Node> _children = new List<Node>();
public Node(Node parent, string info)
{
this._info = info;
this.Parent = parent;
}
public Node Parent { get; set; }
public void AddChild(Node node)
{
if (!this.DoesNodeContainChild(node))
{
node.Parent = this;
_children.Add(node);
}
}
public bool DoesNodeContainChild(Node child)
{
return _children.Contains(child);
}
}
}
Note that this is something I wrote in 2 minutes, and it is problery not good in production, but the 2 main things is that you have a parent node and many children. When you add a child node to a given node, then you make sure that it has its parent node set. Here I first check if the child is allready in the children list before connection the two.
You could make some changes to the code, and make sure that if a child is removed an parent lists that it is allready connected to. I have not done this there.
I have made this to illustrate how it could be used. And it is used many places. Fx clustered indexes in MSSQL uses some sort of this tree like representation. But I am NOT an expert on this subject, so correct me if I am wrong.
I have not implemented the two classes in the GraphCollection class. The downside of my little example is that you if you are going to implement the Find method, then you have to go through the whole graph. You could make a binary tree that only has two children:
namespace MiniTreeLibrary
{
public class SimpleNode
{
private string _info;
private SimpleNode _left;
private SimpleNode _right;
private SimpleNode _parent;
public SimpleNode(Node parent, string info)
{
this._info = info;
this.Parent = parent;
}
public Node Parent { get; private set; }
}
}
I have omitted the insertion of the right and left. Now with this binary tree you could do some pretty darn fast searching, if you wanted!! But that is another discossion.
There is many rules when it comes trees and graphs, and my graph is even a real graph. But I have put these examples here so you can see that it is used alot!! If you want to go more into linear and other data structures, then see this serie of articles. Part 3, 4 and 5 they talks alot more about trees and graphs.

Categories