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

Recursively find all objects of type System.Web.UI.Pair in an object array

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

Problem

I have an object array that contains various types of objects (primitives, strings, other object arrays) at arbitrary levels of nesting. I need to pull all objects of type System.Web.UI.Pair from this array and am having a heck of a time writing the method. This is especially difficult because the Pair class itself can contain other Pairs or enumerable of Pairs.

A picture is worth a thousand words:

(Original URL: http://postimage.org/image/i7fuad3b9/)

Here's the method I came up with, but it feels inelegant and incomplete. Any improvements, especially ones that can leverage LINQ are welcome.

public static IEnumerable Flatten(this object root, List list)
    {
        if (root == null)
        {
            return list;
        }
        if (root is Pair)
        {
            var pair = root as Pair;
            list.Add(pair);
            if (pair.First is IEnumerable)
            {
                Flatten((root as Pair).First, list);
            }
            else if (pair.First is Pair)
            {
                list.Add(pair.First as Pair);
            }
            if (pair.Second is IEnumerable)
            {
                Flatten((root as Pair).Second, list);
            }
            else if (pair.Second is Pair)
            {
                list.Add(pair.Second as Pair);
            }
        }
        if (root.GetType().IsArray || root is IEnumerable)
        {
            foreach (object o in (IEnumerable) root)
            {
                Flatten(o, list);
            }
        }
        return list;
    }

Solution

You might consider making this an extension method on Pair instead of object. You could simplify it to this:

public static IEnumerable Flatten(this Pair p, List toBuild = null)
{
   if (toBuild == null)
      toBuild = new List();

   if (p.First is Pair)
   {
      (p.First as Pair).Flatten(toBuild);
   }
   else if (p.First is IEnumerable)
   {
      foreach (object o in (p.First as IEnumerable).OfType().Where(ob => ob is Pair))
      {
         (o as Pair).Flatten(toBuild);
      }
   }

   //repeat for p.Second

  toBuild.Add(p);
  return toBuild;
}


You can use it like this:

var result = myPair.Flatten();


Or on an IEnumerable:

var result = myList.SelectMany(p => p.Flatten());


Or on a regular IEnumerable:

var result = myList.OfType().Where(o => o is Pair)
  .SelectMany(p => (p as Pair).Flatten());

Code Snippets

public static IEnumerable<Pair> Flatten(this Pair p, List<Pair> toBuild = null)
{
   if (toBuild == null)
      toBuild = new List<Pair>();

   if (p.First is Pair)
   {
      (p.First as Pair).Flatten(toBuild);
   }
   else if (p.First is IEnumerable)
   {
      foreach (object o in (p.First as IEnumerable).OfType<object>().Where(ob => ob is Pair))
      {
         (o as Pair).Flatten(toBuild);
      }
   }

   //repeat for p.Second

  toBuild.Add(p);
  return toBuild;
}
var result = myPair.Flatten();
var result = myList.SelectMany(p => p.Flatten());
var result = myList.OfType<object>().Where(o => o is Pair)
  .SelectMany(p => (p as Pair).Flatten());

Context

StackExchange Code Review Q#13513, answer score: 2

Revisions (0)

No revisions yet.