HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Search for Tree

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
treeforsearch

Problem

Here is a search implementation for my tree. It searches each node in a breadth-first manner first, but it goes deeper in a depth-first manner, in the event it needs to go deeper. I know there may be multiple identical items in the tree (well, not my current use of it, but I still need to presume that), so it just returns the children for the first instance found. If I ever have duplicate items with different children, there will be other things needing change anyway.

For reference, this method is being implemented as part of my tree here: Trees and their uses

public IEnumerable GetChildren(T item)
{
    IEnumerable> itemSet = items.Where(x => item.Equals(x.Value));

    if (itemSet.Count() != 0)
    {
        int index = itemSet.ElementAt(0).Key;

        IEnumerable>> branchSet = branches.Where(x => x.Key == index);
        
        if (branchSet.Count() != 0)
        {
            return branchSet.ElementAt(0).Value.GetChildren();
        }
    }

    foreach (KeyValuePair> kvp in branches)
    {
        IEnumerable coll = kvp.Value.GetChildren(item);

        if (coll != Enumerable.Empty())
        {
            return coll;
        }
    }
    return Enumerable.Empty();
}


I'm sure there are ways I can improve this, although it looks good to me.
Edit:

Some people asked me for clarification on how my search combined the breadth-first and depth-first searches in The 2nd Monitor. Here are some images showing how they each work (the first two taken from Wikipedia):
Breadth-first search:

Depth-first search:

My search:

Solution


  • I would use First() instead of ElementAt(0) as it conveys the intention better.



  • Instead of using something.Count() != 0 you should use something.Any(). This avoids having to iterate over the entire sequence just to find out if there are any items in it.



  • Also you are not interested in the entire itemSet you're just interested in the first one if it exists so you should make use of FirstOrDefault which also provides a predicate overload.



-
This foreach loop:

foreach (KeyValuePair> kvp in branches)
{
     IEnumerable coll = kvp.Value.GetChildren(item);

     if (coll != Enumerable.Empty())
     {
         return coll;
     }
}


can be condensed to:

var result = branches.Select(kvp => kvp.Value.GetChildren(item))
                     .FirstOrDefault(coll => coll != Enumerable.Empty());
return result ?? Enumerable.Empty();


Update: Due to KeyValuePair being a value type to make it a bit neater a little helper is needed:

public static class Extensions
{
    public static bool EqualsDefault(this T obj)
    {
        return EqualityComparer.Default.Equals(obj, default(T));
    }
}


With this the method could be rewritten as:

public IEnumerable GetChildren(T item)
{
    var firstMatch = items.FirstOrDefault(x => item.Equals(x.Value));

    if (!firstMatch.EqualsDefault())
    {
        var branch = branches.FirstOrDefault(x => x.Key == firstMatch.Key);
        if (!branch.EqualsDefault())
        {
            return branch.Value.GetChildren(item);
        }
    }

    var result = branches.Select(kvp => kvp.Value.GetChildren(item))
                         .FirstOrDefault(coll => coll != Enumerable.Empty());
    return result ?? Enumerable.Empty();
}

Code Snippets

foreach (KeyValuePair<int, Tree<T>> kvp in branches)
{
     IEnumerable<T> coll = kvp.Value.GetChildren(item);

     if (coll != Enumerable.Empty<T>())
     {
         return coll;
     }
}
var result = branches.Select(kvp => kvp.Value.GetChildren(item))
                     .FirstOrDefault(coll => coll != Enumerable.Empty<T>());
return result ?? Enumerable.Empty<T>();
public static class Extensions
{
    public static bool EqualsDefault<T>(this T obj)
    {
        return EqualityComparer<T>.Default.Equals(obj, default(T));
    }
}
public IEnumerable<T> GetChildren(T item)
{
    var firstMatch = items.FirstOrDefault(x => item.Equals(x.Value));

    if (!firstMatch.EqualsDefault())
    {
        var branch = branches.FirstOrDefault(x => x.Key == firstMatch.Key);
        if (!branch.EqualsDefault())
        {
            return branch.Value.GetChildren(item);
        }
    }

    var result = branches.Select(kvp => kvp.Value.GetChildren(item))
                         .FirstOrDefault(coll => coll != Enumerable.Empty<T>());
    return result ?? Enumerable.Empty<T>();
}

Context

StackExchange Code Review Q#85742, answer score: 4

Revisions (0)

No revisions yet.