I do recursion to find a long value within a List with multiple children that also can have children.
following method:
public TaxonomyData getTaxonomyData(long taxId, List<TaxonomyData> TaxonomyTree, TaxonomyData output)
{
//find taxid in the taxonomy tree list and return the taxonomydata
foreach (TaxonomyData td in TaxonomyTree)
{
if (td.TaxonomyId == taxId)
{
output = td;
//return td; => when doing a return here means I already found a match so it is not necessary to do all the recursion.
}
else if (td.Taxonomy.Length > 0)
{
getTaxonomyData(taxId, td.Taxonomy.ToList(), output);
}
}
return output;
}
Is it possible when I do return td; (see commented row) that my whole recursion stops?
Thanks
I suspect you want something like:
public TaxonomyData GetTaxonomyData(long taxId, IEnumerable<TaxonomyData> tree)
{
foreach (TaxonomyData td in tree)
{
if (td.TaxonomyId == taxId)
{
return td;
}
else
{
// See if it's in the subtree of td
TaxonomyData data = GetTaxonomyData(taxId, td.Taxonomy);
if (data != null)
{
return data;
}
}
}
// Haven't found it anywhere in this tree
return null;
}
Each return only returns one level, but by checking the return value in the else clause, we can return all the way up the stack when we find the right value.
The final result returned to the caller will be a null reference if it hasn't been found.
Note that I've removed the "output" parameter, which wouldn't have been effective anyway as it wasn't a ref parameter, and isn't as clear as just using the return value.
A linq extension solution i came up with, probably slower but there you go..
public static class Ext
{
public static T SingleOrDefault<T>(this IEnumerable<T> enumerable,Func<T,bool> predicate, Func<T,T> defaultSelector)
where T : class
{
return enumerable.SingleOrDefault(predicate) ?? enumerable.SkipWhile<T>(t=>defaultSelector(t) == null).Select(defaultSelector).SingleOrDefault();
}
public static TaxonomyData Get(this IEnumerable<TaxonomyData> tree, int taxId)
{
return tree.SingleOrDefault(t=> t.TaxonomyId == taxId,t=>t.Taxonomy.Get(taxId));
}
}
Related
In C#, I am currently trying to link one node from a certain LinkedList to another node in another LinkedList. I am trying to make this for a game where tiles are connected in levels stacked on top of eachother. However, changing the Next property in the list gives an error. This is the code:
tileList2.First.Next = tileList1.First;
This is the error;
Property or indexer 'LinkedListNode.Next' cannot be assigned to -- it is read only."
How can I (otherwise) set the Next of this node to the First of the other node? What is causing this error? Is there any workaround?
Every node in the framework implementation of LinkedList has a reference to the list containing it, which makes transferring elements to another list O(n) instead of O(1), which defeats the purpose of the linked list implementation. If you want to transfer elements to another list in this implementation, you would have to remove and add them one by one (using Remove and AddAfter on the list) so that they each get a reference to the other list.
I suspect this is not what you're after, though. As other comments state, the needs of your list are probably simple enough that you'd be better off making your own much simpler linked list. And that question is already addressed elsewhere on SO (Creating a very simple linked list).
Since that answer doesn't include easy enumeration and initialization, I made my own.
class ListNode<T> : IEnumerable<T>
{
public T data;
public ListNode<T> Next;
private ListNode() { }
public ListNode(IEnumerable<T> init)
{
ListNode<T> current = null;
foreach(T elem in init)
{
if (current == null) current = this; else current = current.Next = new ListNode<T>();
current.data = elem;
}
}
class ListEnum : IEnumerator<T>
{
private ListNode<T> first;
private ListNode<T> current;
bool more;
public ListEnum(ListNode<T> first) { this.first = first; more = true; }
public T Current { get { return current.data; } }
public void Dispose(){}
object System.Collections.IEnumerator.Current { get { return current.data; } }
public void Reset() { current = null; more = true; }
public bool MoveNext()
{
if (!more)
return false;
else if (current == null)
return more = ((current = first) != null);
else
return more = ((current = current.Next) != null);
}
}
public IEnumerator<T> GetEnumerator()
{
return new ListEnum(this);
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
static void Main(string[] args)
{
ListNode<int> l1 = new ListNode<int>(new int[] {3,1,4,1,5,9});
ListNode<int> l2 = new ListNode<int>(new int[] { 5 });
l2.Next = l1.Next;
foreach (int i in l2)
Console.WriteLine(i);
}
you can't set LinkedListNode.Next directly, it is readonly.
you also can't use LinkedList.AddLast because the LinkedlListNode you are trying to add is already in a list.
you actually need to break the lists and create new ones.
or you could implement your own linked list.
I have a Item[] _items array of items, where some of the items may be null. I wish to check if the array contains at least one non-null item.
My current implementations seems a little complicated:
internal bool IsEmtpy { get { return (!(this.NotEmpty)); } }
private bool IsNotEmpty { get { return ( this.Items.Any(t => t != null));} }
So my question is: Is there a simpler way to check if a typed array of reference objects contains at least one non null object?
There is no complexity in your implementation. Basically, the only way to check whether there are non-null values in the array is to look through all values until you will reach non-null value or the end of the array.
The following code is easier to understand though:
internal bool IsEmtpy { get { return this.Items.All(t => t == null); } }
private bool IsNotEmpty { get { return this.Items.Any(t => t != null); } }
And it is probably better to extend IEnumerable as follows:
public static class Extensions {
public static bool ContainsOnlyEmpty<TSource>(this IEnumerable<TSource> source) {
return source.All(t => t == null);
}
public static bool ContainsNonEmpty<TSource>(this IEnumerable<TSource> source) {
return source.Any(t => t != null);
}
}
and use it like this: bool nonEmpty = this.Items.ContainsNonEmpty();
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;
}
}
I have a method in C# that finds a node with name node_name in node list arg, and returns the value of found node (assuming there's only one node with such name). If no such nodes are found, it should return an empty string.
public string get_nodes_value(XmlNodeList arg, string node_name)
{
foreach (XmlNode arg_node in arg)
{
if (!arg_node.HasChildNodes)
{
if (String.Compare(arg_node.ParentNode.Name, node_name) == 0)
{
return arg_node.Value;
}
}
else
{
get_nodes_value(arg_node.ChildNodes, node_name);
}
}
return "";
}
The code above always returns an empty string. What did I miss here?
Well, you're ignoring the return value of the recursive call in the else block. Did you mean to return from there in some cases? My guess is you want something like this (fixing a few convention oddities at the same time):
public string GetNodeValue(XmlNodeList list, string name)
{
foreach (XmlNode node in list)
{
if (!node.HasChildNodes)
{
if (node.ParentNode.Name == name)
{
return arg_node.Value;
}
}
else
{
// Only return if we've found something within this node's child list
string childValue = GetNodeValue(node.ChildNodes, name);
if (childValue != "")
{
return childValue;
}
}
}
return "";
}
Whichever recursive invocation finds your node will return it, but unless it's the top-level that value just gets ignored. You probably meant to do something like:
else
{
string value = get_nodes_value(arg_node.ChildNodes, node_name);
if (value != "")
return value;
}
The easiest way to find that out would be to step through the code while setting up "watches" on arg_node.ParentNode.Name and node_name and then you'll see which branches it'll end up in and you can find out why it didn't go where you thought it would go.
I've got a simple class defined as:
public class IndexEntry
{
public bool HighScore { get; set; }
public List<IndexEntry> SubEntries { get; set; }
//Other properties, etc...
}
I now need to search through a List to find the one item that has its HighScore Property set to true. Since it isn't a flat list, but a Hierarchy which can be an unknown number of levels deep and since the item I'm looking for might be contained in any one of the SubEnties lists, I can't do a simple Lambda like this:
var foundHighScore = myList.FirstOrDefault(IE => IE.HighScore == true);
Here's the code I have. I know it's ugly (at least it seems that way to me). It works, but is slow as sin on an even remotely large list and I'm sure there must be a better way.
private IndexEntry GetHighScoreEntry(IEnumerable<IndexEntry> entryList)
{
IndexEntry result = null;
IndexEntry recursiveResult = null;
foreach (IndexEntry currentEntry in entryList)
{
if (currentEntry.HighScore)
{
result = currentEntry;
break; //Don't need to look anymore, we found our highscore.;
}
else
{
if ((currentEntry.SubEntries == null) || (currentEntry.SubEntries.Count < 1))
{
continue;
}
else
{
recursiveResult = GetHighScoreEntry(currentEntry.SubEntries);
if (recursiveResult == null)
continue;
result = recursiveResult;
break;
}
}
}
return result;
}
I've got believe that there's a better way using a slightly more complex lambda or with LINQ to clean up this code and make it more performant.
Thanks in advance for your help.
All the solutions posted so far are specialized - they are not generic or general, and thus, the next time you have a hierarchical list, you'll have to code up a new solution. Yuck.
Here's a general, generic solution that will work for all your hierarchical needs:
public static IEnumerable<T> Flatten<T>(this IEnumerable<T> sequence, Func<T, IEnumerable<T>> childFetcher)
{
var itemsToYield = new Queue<T>(sequence);
while (itemsToYield.Count > 0)
{
var item = itemsToYield.Dequeue();
yield return item;
var children = childFetcher(item);
if (children != null)
{
foreach (var child in children)
{
itemsToYield.Enqueue(child);
}
}
}
}
Here's how you'd use it:
myList.Flatten(i => i.SubEntries).FirstOrDefault(i => i.HighScore);
Easy as cheese.
This extension method can be used to turn any hierarchical data into a flat list, which can them be searched using LINQ.
Another great thing about this solution is that is uses lazy evaluation, thus it only does as much work as the caller demands. For example, in the above code, Flatten will stop churning out items as soon as a HighScore is found.
This solution also avoids recursion, which can be a costly operation for deeply nested hierarchies, avoiding the many stack allocations that recursive solutions incur.
Recursion is your friend here.
public IndexEntry FindHighScore(IEnumerable<IndexEntry> entries)
{
foreach (IndexEntry entry in entries)
{
IndexEntry highScore = FindHighScore(entry);
if (highScore != null)
{
return highScore;
}
}
return null;
}
private IndexEntry FindHighScore(IndexEntry entry)
{
return entry.HighScore ? entry : FindHighScore(entry.SubEntries);
}
You could significantly narrow your search down with a lambda expression something like:
var foundHighScore = myList.FirstOrDefault(IE => IE.HighScore or (IE.SubEntries != null && IE.SubEntries.Any(IES => IES.HighScore));
var indexEntry = foundHighScore;
if (!indexEntry.HighScore)
{
indexEntry = indexEntry.SubEntries.FirstOrDefault(IE => IE.HighScore);
}
// do something with indexEntry
Update
Actually the first solution won't traverse through properly. I don't think there is a lambda-only solution to this, you will have to do some form of recursive function. Off the top of my head the following would work, how it would cope performance wise I am unsure:
public IndexEntry FindHighScore(List<IndexEntry> entries)
{
var highScore = GetHighScore(entries);
if (highScore == null)
{
// give me only entries that contain sub-entries
var entriesWithSub = entries.Where(e => e.SubEntries != null);
foreach (var e in entriesWithSub)
{
highScore = FindHighScore(e.SubEntries);
if (highScore != null)
return highScore;
}
}
return highScore;
}
private IndexEntry GetHighScore(List<IndexEntry> entries)
{
return entries.FirstOrDefault(IE => IE.HighScore);
}