Traverse up a list using Linq - c#

I have a class as follows:
public class SiloNode
{
public string Key { get; private set; }
public string ParentKey { get; private set; }
public string Text { get; private set; }
public string Url { get; private set; }
}
All nodes are contained in a list:
List<SiloNode> nodes = new List<SiloNode>();
As you can see, the class contains a ParentKey property, so it's possible to find the item's parent, grandparent etc, until the top of the list is hit.
At present, I need to traverse up 2 levels, and you can see from the code below, it's already looking quite clunky. Now I need to modify the code to traverse up 3 levels and I'm concerned it's getting messy.
Is there a cleaner way to achieve what I want?
string GetStartGroup(string currentUrl)
{
string startGroup = null;
var currentNode = Silos.Silo.SingleOrDefault(x => x.Url == currentUrl);
if (currentNode != null)
{
var parentNode = Silos.Silo.SingleOrDefault(x => x.Key == currentNode.ParentKey);
if (parentNode != null) startGroup = parentNode.ParentKey;
}
return startGroup;
}

Repeatedly using SingleOrDefault on a list makes the algorithm rather slow: finding parents for n nodes requires an O(n2) time.
You should make a Dictionary<string,SiloNode> first, and then traverse up the hierarchy through the dictionary:
var lookup= nodes.ToDictionary(n => n.Key);
...
SiloNode FindParent(SiloNode node, int levelsUp, IDictionary<string,SiloNode> lookup) {
while (node != null && levelsUp != 0) {
if (node.ParentKey == null || !lookup.TryGetValue(node.ParentKey, out var parent)) {
return node;
}
node = parent;
levelsUp--;
}
return node;
}
This will look up a parent up to levelsUp levels up. If you are looking for the last possible parent, modify the code as follows:
SiloNode FindParent(SiloNode node, IDictionary<string,SiloNode> lookup) {
while (true) {
if (node?.ParentKey == null || !lookup.TryGetValue(node.ParentKey, out var parent)) {
return node;
}
node = parent;
}
}
or recursively
SiloNode FindParent(SiloNode node, IDictionary<string,SiloNode> lookup) {
return node?.ParentKey != null && lookup.TryGetValue(node.ParentKey, out var parent)
? FindParent(parent, lookup)
: node;
}

You can do this with recursion.
string GetStartGroup(string currentUrl)
{
var node = nodes.Single(x => x.Url == currentUrl);
if (node.ParentKey == null)
return node.Key;
return GetStartGroup(nodes.Single(x => x.Key == node.ParentKey).Url);
}
Alternatively:
string GetStartGroup(string currentUrl)
{
return GetStartNode(nodes.Single(x => x.Url == currentUrl)).Key;
}
SiloNode GetStartNode(SiloNode node)
{
if (node.ParentKey == null)
return node;
return GetStartNode(nodes.Single(x => x.Key == node.ParentKey));
}

You can change
if (parentNode != null) startGroup = parentNode.ParentKey;
to
if (parentNode != null) startGroup = GetStartGroup(currentNode.parentUrl /*or something similar*/);
However, it would be better to use an iterative loop. I do not know about your problem enough to give you a hint, but the pseudocode would look like this:
while (parentNode != null) {
currentNode = currentNode.parentNode;
parentNode = currentNode.parentNode;
}
You might need to call SingleOrDefault, but if you have a direct reference, you should use that instead.

just put it into a method:
public static Silo Up(Silo current, IEnumerable<Silo> collection)
{
return collection.FirstOrDefault((it) => it.ParentKey == it.Key);
}
or as Extension method:
public static SiloExtensions
{
public static Silo Up(this Silo current, IEnumerable<Silo> collection)
{
return collection.FirstOrDefault((it) => it.ParentKey == it.Key);
}
}
so you can just do silo.Up()?.Up()
Please note that this is rather slow.
Depending on what you actually do, you may want to introduce actual Parent-Object as a field or a wrapper object providing access to it.
Such a wrapper object might look like this:
public class SiloWrapper
{
public Silo Wrapped { get; }
public Silo Parent { get; }
private SiloWrapper(Silo silo, Silo parent)
{
this.Wrapped = silo;
this.Parent = parent;
}
public IEnumerable<SiloWrapper> Map(IEnumerable<Silo> silos)
{
var dict = silos.ToDictionary((s) => s.Key);
foreach(var s in silos)
{
yield return new SiloWrapped(s, s.ParentKey == null ? null : dict[s.ParentKey]);
}
}
}
to then traverse up and down, you just would need to call SiloWrapped.Map(<methodToGetSiloCollection>) and have all wrapped silos ready for usage.
If GarbageCollection may be a concern, you also can use WeakReference<Silo> ParentWeak instead

Related

Printing Tree and skipping certain values

here i have the following code and input that prints a tree structure. My question is how can i make it so that the nodes and leafs that have the value "Unavailable" are skipped from being printed.
namespace Tree{public class TreeNode<T>
{
private T value;
private bool hasParent;
private List<TreeNode<T>> children;
public TreeNode(T value)
{
if (value == null)
{
throw new ArgumentNullException("Cannot insert null value");
}
this.value = value;
this.children = new List<TreeNode<T>>();
}
public T Value
{
get
{
return this.value;
}
set
{
this.value = value;
}
}
public int ChildrenCount
{
get
{
return this.children.Count;
}
}
public void AddChild(TreeNode<T> child)
{
if (child == null)
{
throw new ArgumentNullException("Cannot insert null value");
}
if (child.hasParent)
{
throw new ArgumentException("The node already has a parent");
}
child.hasParent = true;
this.children.Add(child);
}
public TreeNode<T> GetChild(int index)
{
return this.children[index];
}
}
public class Tree<T>
{
private TreeNode<T> root;
public Tree(T value)
{
if (value == null)
{
throw new ArgumentNullException("Cannot insert null value");
}
this.root = new TreeNode<T>(value);
}
public Tree(T value, params Tree<T>[] children) : this(value)
{
foreach (Tree<T> child in children)
{
this.root.AddChild(child.root);
}
}
public TreeNode<T> Root
{
get
{
return this.root;
}
}
private void PrintDFS(TreeNode<T> root, string spaces)
{
if (this.root == null)
{
return;
}
Console.WriteLine(spaces + root.Value);
TreeNode<T> child = null;
for (int i = 0; i < root.ChildrenCount; i++)
{
child = root.GetChild(i);
PrintDFS(child, spaces + " ");
}
}
public void TraverseDFS()
{
this.PrintDFS(this.root, string.Empty);
}
}
public static class TreeExample
{
static void Main()
{
Tree<string> tree =
new Tree<string>("John",
new Tree<string>("Jasmine",
new Tree<string>("Jay"),
new Tree<string>("Unavailable")),
new Tree<string>("Unavailable",
new Tree<string>("Jack"),
new Tree<string>("Jeremy")),
new Tree<string>("Johanna")
);
tree.TraverseDFS();
}
}}
right now it prints :(John, (Jasmine, (Jay), (Unavailable)), (Unavailable, (Jack, (Jeremy))), (Johanna))
I need it to print :(John, (Jasmine, (Jay)), (Johanna))
So basically skip every leaf with the value "Unavailable" and every node with the value "Unavailable" and all children from that node
Thanks !
This should work:
private void PrintDFS(TreeNode<T> root, string spaces)
{
if (this.root == null
|| "Unavailable" == root.Value.ToString())
{
return;
}
...
The accepted answer is a literally correct answer to the question, but it bakes in logic about what to do with the tree into the tree itself. A tree is a kind of collection or data structure, and you don't often see a List or Dictionary that is able to print itself. Instead the collection provides the right methods to get or change its contents so that you can do what you want.
In your case, you could do something like the following:
public enum TreeVisitorResult {
SkipNode,
Continue
}
// the following two methods inside Tree<T>:
public void VisitNodes(Func<TreeNode<T>, int, TreeVisitorResult> visitor) {
VisitNodes(0, this.root, visitor);
}
private void VisitNodes(int depth, TreeNode<T> node,
Func<TreeNode<T>, int, TreeVisitorResult> visitor) {
if (node == null) {
return;
}
var shouldSkip = visitor(node, depth);
if (shouldSkip == TreeVisitorResult.SkipNode) {
return;
}
TreeNode<T> child = null;
for (int i = 0; i < node.ChildrenCount; i++) {
child = node.GetChild(i);
VisitNodes(depth + 1, child, visitor);
}
}
If you had this method, you could write the Print method outside of the Tree classes, as:
tree.VisitNodes((treeNode, depth) => { // <- this lambda will be called for every node
if (treeNode.Value == "Unavailable") { // <- no need to ToString or cast here, since
// we know that T is string here
return TreeVisitorResult.SkipNode;
} else {
var spaces = new string(' ', depth * 3);
Console.WriteLine(spaces + treeNode.Value);
}
});

Search tree, simplest method for traversing c#

I need to be able to search a tree with arbitrary many children.
It could look like this.
P
/ | \
C C C layer 1
/ | \
C C C layer 2
|
C layer 3
/ | \
C C C layer 4
With arbitrary many children in each C.
Is it convinient to have a double linked list for each start node in layer 1? (In layer 1 the non expanding nodes might also ofcourse expand).
I need to evaluate and work with every sub-tree.
Whats the simplest method?
Or maybe some kind of depth first search/breadth first search is better?
The tree is constructed on the fly.
thanks
The easiest way to do this is using recursion.
Let's assume that your tree stores items of type T, and that type implements IEquatable<T>.
Firstly, let's write a very basic tree class:
public sealed class Node<T>
{
public Node(T value) { Value = value; }
public T Value { get; }
public IEnumerable<Node<T>> Children => _children;
public void Add(Node<T> child)
{
_children.Add(child);
}
readonly List<Node<T>> _children = new List<Node<T>>();
}
Now we can write a method to search that tree using recursion very simply.
This will return the first node containing the specified value if it was found, or null if no such node was found.
public static Node<T> Find<T>(Node<T> root, T target) where T: IEquatable<T>
{
if (root.Value != null && root.Value.Equals(target))
return root;
foreach (var child in root.Children)
{
var found = Find(child, target);
if (found != null)
return found;
}
return null;
}
It's easy to adapt this to return ALL nodes that match the target:
public static IEnumerable<Node<T>> FindAll<T>(Node<T> root, T target) where T : IEquatable<T>
{
if (root.Value != null && root.Value.Equals(target))
yield return root;
foreach (var child in root.Children)
{
var found = FindAll(child, target);
foreach (var item in found)
yield return item;
}
}
For demo purposes, here's a compilable console application. It includes a makeTree() method which I'm using to make a tree of depth 4 where each node has 5 children.
Then it uses Find<T>(Node<T> root, T target) to recursively search the tree to find the specified target values. One will succeed, the other will fail:
using System;
using System.Collections.Generic;
namespace Demo
{
public sealed class Node<T>
{
public Node(T value) { Value = value; }
public T Value { get; }
public IEnumerable<Node<T>> Children => _children;
public void Add(Node<T> child)
{
_children.Add(child);
}
readonly List<Node<T>> _children = new List<Node<T>>();
}
class Program
{
static void Main()
{
var root = makeTree(1, 1, 4, 5);
lookFor(root, "3.4");
lookFor(root, "6.3");
}
static void lookFor<T>(Node<T> root, T target) where T: IEquatable<T>
{
var found = Find(root, target);
Console.WriteLine(found != null ? $"Found {target}" : $"Did not find {target}");
}
public static Node<T> Find<T>(Node<T> root, T target) where T: IEquatable<T>
{
if (root.Value != null && root.Value.Equals(target))
return root;
foreach (var child in root.Children)
{
var found = Find(child, target);
if (found != null)
return found;
}
return null;
}
static Node<string> makeTree(int id1, int id2, int depth, int nChildren)
{
var root = new Node<string>($"{id1}.{id2}");
if (depth == 0)
return root;
for (int i = 0; i < nChildren; ++i)
root.Add(makeTree(id1+1, i+1, depth-1, nChildren));
return root;
}
}
}

how to find a NodeData in tree of Nodes?

I have a Node structure as below,this Node has stringdata and list of nodes as it's children. I wanted to search a data in this tree
I wrote a recursive function FindNode(Node intree,string target)
public class Node
{
public string Data;
public List<Node> Children = new List<Node>();
//some code
public Node(string r)
{
this.Data = r;
}
public string getData()
{
return this.Data;
}
//some code
public List<Node> getchildren()
{
return this.Children;
}
//some code
}
target is the string which I want to find and the intree is the begining of the tree(ROOT)
I have problem after while loop what should I return after that?
If I am wrong how should I write it?
public Node FindNode(Node intree,string target)
{
if(intree.getData()==target)
return intree;
else
{
while(intree.getchildren()!=null)
{
foreach(Node n in intree.getchildren())
{
FindNode(n,target);
}
}
}
}
Use this one:
public Node FindNode(Node intree,string target)
{
if(intree.getData()==target)
return intree;
else
{
foreach(Node n in intree.getchildren())
{
Node node = FindNode(n,target) ; //CHECK FOR RETURN
if(node != null)
return node;
}
}
return null;
}
The difference is that I checked for return of FindNode method, and if it's not null, return result.
Just note that in case of dupplicated nodes in the tree (nodes with the same string) it will return first occuarance.
Given that there could be more than one match in the tree you would be better off returning an IEnumerable<Node>. Also you don't need to put those odd get methods in there. And finally did you mean to only search leaf nodes or did you want to search all nodes (the else statement)?
public IEnumerable<Node> FindNode(Node intree,string target)
{
if(intree.Data ==target)
yield return intree;
foreach (var node in intree.Children.SelectMany(c => FindNode(c, target))
yield return node;
}
If you want the first matching node, just call First() on the result. If you want to make sure there is only one, call Single() on it.
I would recommend you to return null and apply check where you are calling this method that if null is returned then it means no node found. Code is as follow
public static Node FindNode(Node intree, string target)
{
if (intree.getData() == target)
return intree;
foreach (Node node in intree.getchildren())
{
Node toReturn = FindNode(node, target);
if (toReturn != null) return toReturn;
}
return null;
}
public Node FindNodeRecursively(Node parentNode, string keyword)
{
if(parentNode.getData() == keyword)
{
return parentNode;
}
else
{
if(parentNode.Children != null)
{
foreach(var node in parentNode.Children)
{
var temp = FindNodeRecursively(node, keyword);
if(temp != null)
return temp;
}
}
return null;
}
}

Possible NullReferenceException

For example this snippet of code:
private void LoadComments(Member member, XElement commentsXml)
{
member.Comments = (from comment in commentsXml.Descendants("comment")
select new Comment()
{
ID = comment.Element("id").Value,
Text = comment.Element("text").Value,
Date = comment.Element("date").Value,
Owner = comment.Element("user").Element("name").Value
}).ToList();
}
ReSharper warns me of a possible NullReferenceException on the comment.Element lines. True enough, the exception fired.
Any suggestion of how to avoid this? What about if it returns null, just return an empty string, is this possible?
I Prefer to have an extension class for it:
public static class XElementExtension
{
public static string GetValue(this XElement input)
{
if (input == null)
return null;
return input.Value as T;
}
public static XElement GetSubElement(this XElement element, string id)
{
if (element == null)
return null;
return element.Element(id);
}
}
and use it as :
ID = comment.Element("id").GetValue()
or
Owner = comment.Element("user").GetSubElement("name").GetValue()
Also there are other ways like:
http://www.codeproject.com/KB/cs/maybemonads.aspx
A few extensions could help:
Example:
public static class XElementExtensions
{
public static XElement GetElement(this XElement element, XName elementName)
{
if (element != null)
{
XElement child = element.Element(elementName);
if (child != null)
{
return child;
}
}
return null;
}
public static String GetElementValue(this XElement element, XName elementName)
{
if (element != null)
{
XElement child = element.Element(elementName);
if (child != null)
{
return child.Value;
}
}
return null;
}
}
Usage:
private void LoadComments(Member member, XElement commentsXml)
{
member.Comments = (from comment in commentsXml.Descendants("comment")
select new Comment()
{
ID = comment.GetElementValue("id"),
Text = comment.GetElementValue("text"),
Date = comment.GetElementValue("date"),
Owner = comment.GetElement("user").GetElementValue("name")
}).ToList();
}
I can only think you'd need to check each element reference thus:
private void LoadComments(Member member, XElement commentsXml)
{
member.Comments = (from comment in commentsXml.Descendants("comment")
select new Comment()
{
ID = (comment.Element("id")==null)?"":comment.Element("id").Value,
Text = (comment.Element("text")==null)?"":comment.Element("text").Value,
Date = (comment.Element("date")==null)?"":comment.Element("date").Value,
Owner = (comment.Element("user")==null)?"":comment.Element("user").Element("name").Value
}).ToList();
}
The last is a little weak as there's two nodes that really should be checked but the nesting would look a little unpleasant but the only way to be sure.
EDIT ----
As an extension method:
public static class MyExtensions
{
public static string ValueSafe(this XElement target)
{
if (target==null)
{ return ""; }
else
{ return target.Value; }
}
}
You can then replace .Value with .ValueSafe, that said, not had an opportunity to test.
It is possible - you would need to wrap each comment.Element().Value statement in a function.
I like to use:
public string UnNull(object v)
{
if (v == null) return "";
return v.ToString();
}
As for the last line, you need to be extra carful there to make sure comment.Element("user") is not null and handle that case if it is.

C# - LinkedList - How to remove all nodes after specified node?

I am implementing an undo/redo buffer with generic LinkedList.
In this state:
[Top]
state4 (undone)
state3 (undone)
state2 <-- current state
state1
[bottom]
When I do a Push, I would like to remove all states after the current one, and push the new one.
My current bypass is to do while (currentState != list.last), list.removeLast(); but it sucks
LinkedList just support Remove, RemoveFirst & removeLast...
I would like something like RemoveAllNodesAfter(LinkedListNode ...) ?
How can I code that nicely, without iterating throught all nodes ? Maybe with extensions ?...
I can't see anything in the standard LinkedList<T> which lets you do this. You could look in PowerCollections and the C5 collections if you want - or just roll your own LinkedList type. It's one of the simpler collections to implement, especially if you can add functionality in a "just in time" manner.
If I were to implement this myself, I would chose a different way to implement this.
Instead of the .RemoveAllNodesAfter(node) method, I would opt to make a .SplitAfter(node) method that returned a new linked list starting with the next node after node. This would make a handier tool than just being able to chop off the tail. If you wanted your RemoveAllNodesAfter method, it would just have to call the SplitAfter method internally and discard the result.
Naive implementation:
public LinkedList<T> SplitAfter(Node node)
{
Node nextNode = node.Next;
// break the chain
node.Next = null;
nextNode.Previous = null;
return new LinkedList<T>(nextNode);
}
public void RemoveAllNodesAfter(Node node)
{
SplitAfter(node);
}
Linked List (especially the singly linked list) is one of the most basic fundamental collection structures. I'm certain that you could probably implement it (and add the behavior your need) with little effort.
In reality, you don't actually need a collection class to manage the list. You could manage the nodes without a collection class.
public class SingleLinkedListNode<T>
{
private readonly T value;
private SingleLinkedListNode<T> next;
public SingleLinkedListNode(T value, SingleLinkedListNode<T> next)
{
this.value = value;
}
public SingleLinkedListNode(T value, SingleLinkedListNode<T> next)
: this(value)
{
this.next = next;
}
public SingleLinkedListNode<T> Next
{
get { return next; }
set { next = value; }
}
public T Value
{
get { return value; }
}
}
If you're interested in a possible implementation, however, here's a somewhat simple SingleLinkedList implementation.
public class SingleLinkedList<T>
{
private SingleLinkedListNode<T> head;
private SingleLinkedListNode<T> tail;
public SingleLinkedListNode<T> Head
{
get { return head; }
set { head = value; }
}
public IEnumerable<SingleLinkedListNode<T>> Nodes
{
get
{
SingleLinkedListNode<T> current = head;
while (current != null)
{
yield return current;
current = current.Next;
}
}
}
public SingleLinkedListNode<T> AddToTail(T value)
{
if (head == null) return createNewHead(value);
if (tail == null) tail = findTail();
SingleLinkedListNode<T> newNode = new SingleLinkedListNode<T>(value, null);
tail.Next = newNode;
return newNode;
}
public SingleLinkedListNode<T> InsertAtHead(T value)
{
if (head == null) return createNewHead(value);
SingleLinkedListNode<T> oldHead = Head;
SingleLinkedListNode<T> newNode = new SingleLinkedListNode<T>(value, oldHead);
head = newNode;
return newNode;
}
public SingleLinkedListNode<T> InsertBefore(T value, SingleLinkedListNode<T> toInsertBefore)
{
if (head == null) throw new InvalidOperationException("you cannot insert on an empty list.");
if (head == toInsertBefore) return InsertAtHead(value);
SingleLinkedListNode<T> nodeBefore = findNodeBefore(toInsertBefore);
SingleLinkedListNode<T> toInsert = new SingleLinkedListNode<T>(value, toInsertBefore);
nodeBefore.Next = toInsert;
return toInsert;
}
public SingleLinkedListNode<T> AppendAfter(T value, SingleLinkedListNode<T> toAppendAfter)
{
SingleLinkedListNode<T> newNode = new SingleLinkedListNode<T>(value, toAppendAfter.Next);
toAppendAfter.Next = newNode;
return newNode;
}
public void TruncateBefore(SingleLinkedListNode<T> toTruncateBefore)
{
if (head == toTruncateBefore)
{
head = null;
tail = null;
return;
}
SingleLinkedListNode<T> nodeBefore = findNodeBefore(toTruncateBefore);
if (nodeBefore != null) nodeBefore.Next = null;
}
public void TruncateAfter(SingleLinkedListNode<T> toTruncateAfter)
{
toTruncateAfter.Next = null;
}
private SingleLinkedListNode<T> createNewHead(T value)
{
SingleLinkedListNode<T> newNode = new SingleLinkedListNode<T>(value, null);
head = newNode;
tail = newNode;
return newNode;
}
private SingleLinkedListNode<T> findTail()
{
if (head == null) return null;
SingleLinkedListNode<T> current = head;
while (current.Next != null)
{
current = current.Next;
}
return current;
}
private SingleLinkedListNode<T> findNodeBefore(SingleLinkedListNode<T> nodeToFindNodeBefore)
{
SingleLinkedListNode<T> current = head;
while (current != null)
{
if (current.Next != null && current.Next == nodeToFindNodeBefore) return current;
current = current.Next;
}
return null;
}
}
Now you can do this:
public static void Main(string[] args)
{
SingleLinkedList<string> list = new SingleLinkedList<string>();
list.InsertAtHead("state4");
list.AddToTail("state3");
list.AddToTail("state2");
list.AddToTail("state1");
SingleLinkedListNode<string> current = null;
foreach (SingleLinkedListNode<string> node in list.Nodes)
{
if (node.Value != "state2") continue;
current = node;
break;
}
if (current != null) list.TruncateAfter(current);
}
The thing is depending on your situation, it's not much better than this:
public static void Main(string[] args)
{
SingleLinkedListNode<string> first =
new SingleLinkedListNode<string>("state4");
first.Next = new SingleLinkedListNode<string>("state3");
SingleLinkedListNode<string> current = first.Next;
current.Next = new SingleLinkedListNode<string>("state2");
current = current.Next;
current.Next = new SingleLinkedListNode<string>("state1");
current = first;
while (current != null)
{
if (current.Value != "state2") continue;
current.Next = null;
current = current.Next;
break;
}
}
This eliminates the need for the collection class altogether.
Alternatively, you can do this:
while (currentNode.Next != null)
list.Remove(currentNode.Next);
Actually, a linked list is a fairly trivial data structure to implement especially in managed code (read: no memory management hassle).
Here's one I hacked up that support just enough functions (read: YAGNI) to support your undo/redo operations:
public class LinkedListNode<T>
{
public LinkedList<T> Parent { get; set; }
public T Value { get; set; }
public LinkedListNode<T> Next { get; set; }
public LinkedListNode<T> Previous { get; set; }
}
public class LinkedList<T> : IEnumerable<T>
{
public LinkedListNode<T> Last { get; private set; }
public LinkedListNode<T> AddLast(T value)
{
Last = (Last == null)
? new LinkedListNode<T> { Previous = null }
: Last.Next = new LinkedListNode<T> { Previous = Last };
Last.Parent = this;
Last.Value = value;
Last.Next = null;
return Last;
}
public void SevereAt(LinkedListNode<T> node)
{
if (node.Parent != this)
throw new ArgumentException("Can't severe node that isn't from the same parent list.");
node.Next.Previous = null;
node.Next = null;
Last = node;
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable<T>)this).GetEnumerator();
}
public IEnumerator<T> GetEnumerator()
{
var walk = Last;
while (walk != null) {
yield return walk.Value;
walk = walk.Previous;
}
}
}
Then you can use the SevereAt method in your code to "cut" the linked list nice and simple.
The first idea that springs to mind is to set Node.Next.Previous = null (if it's a doubly-linked list) and then Node.Next = null .
Unfortunately, because LinkedListNode<T>.Next and LinkedListNode<T>.Previous are read-only properties in the .NET implementation of Linked List, I think you may have to implement your own structure to achieve this functionality.
But as others have said, that should be easy enough. There are plenty of resources you can use as a starting point if you just Google for linked lists C#.
if(this.ptr != null && this.ObjectName != null)
{
LinkedListNode<ObjectType> it = ObjectName.Last;
for (; it != this.ptr; it = it.Previous)
{
this.m_ObjectName.Remove(it);
}
}
this.ptr is of type LinkedListNode<ObjectType> just fyi
this.ptr is a pointer pointing to the node you are currently at, I'm assuming you want to delete everything to the right of it.
Don't make a new copy of your structure, its the worst idea ever. It is a complete memory hog and the structure could be extremely large. Copying the Object is not good programming practice unless its absolutely necessary. Try to do in-place operations.
I've made two extension methods for "removing all nodes before specific node" and "removing all nodes after specific node". However, these extension methods are extensions of LinkedListNode, not LinkedList itself, just for convenience:
public static class Extensions
{
public static void RemoveAllBefore<T>(this LinkedListNode<T> node)
{
while (node.Previous != null) node.List.Remove(node.Previous);
}
public static void RemoveAllAfter<T>(this LinkedListNode<T> node)
{
while (node.Next != null) node.List.Remove(node.Previous);
}
}
Example of use:
void Main()
{
//create linked list and fill it up with some values
LinkedList<int> list = new LinkedList<int>();
for(int i=0;i<10;i++) list.AddLast(i);
//pick some node from the list (here it is node with value 3)
LinkedListNode<int> node = list.First.Next.Next.Next;
//now for the trick
node.RemoveAllBefore();
//or
node.RemoveAllAfter();
}
Well it's not the most effective approach and if you find yourself calling this method on large lists or very often, then other here described approaches are probably more fit (like writing your own linked list class which allows splitting as described in other answers) but if it is just occassional "remove node here and there" than this is simple and quite intuitive.

Categories