Amit
Amit

Reputation: 321

Recursive query using LINQ

Is it possible to write this in LINQ? I tried using LINQ. However, I figured it will have to be looped twice; first to verify whether a is present and next to iterate through qs.

So I came up with this code.

public a Traverse(List<q> qs,string id)
    {

        foreach (var q in qs)
        {
            if (q.as.Any(a => a.Id == id))
            {
                return q.as.First(a => a.Id == id);

            }

            foreach (var a in q.as)
            {
                var result =Traverse(a.qs, id);
                if(result != null)
                  return result;
            }
        }
        return null;
    }  

I am reading it from XML which is like "q" have "a" and "a" have "q" in recursive manner.

I need to find unique Id belonging to a.

I know there have been discussions on other threads but they were not helpful.

EDIT: Here's snippet of XML

  <qs xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <qs>
    <q>q 1</q>
    <Id>1</Id>
    <as>
      <a>
        <aprop>a</aprop>
        <Id>a 1.1</Id>
        <qs>
          <q>
            <q>q 1.1.1</q>
            <Id>1.1.1</Id>
            <as>
              <a>
                <a>a</a>
                <Id>a 1.1.1.1</Id>
                <qs />
                <type>1</type>
              </a>
              <a>
                <a>a</a>
                <Id>a 1.1.1.2</Id>
                <qs />
                <type>1</type>
              </a>
            </as>
          </q>
          <q>
            <q>q 1.1.2</q>
            <Id>1.1.2</Id>
            <as>
              <a>
                <a>a</a>
                <Id>a 1.1.2.1</Id>
                <qs />
                <type>1</type>
              </a>
              <a>
                <a>a</a>
                <Id>a 1.1.2.2</Id>
                <qs />
                <type>1</type>
              </a>
            </as>
          </q>

Upvotes: 2

Views: 3948

Answers (4)

Ray Saltrelli
Ray Saltrelli

Reputation: 4218

If LINQ to XML will work for you then MarcinJuraszek's answer is perfect. To address your LINQ to Objects question, what about something like this?

    public a Traverse(IQueryable<q> qList, string id)
    {
        return this.GatherAs(qList).FirstOrDefault(a => a.Id == id);
    }

    public IQueryable<a> GatherAs(IQueryable<q> qList)
    {
        IQueryable<a> aList = qList.SelectMany(q => q.aList);

        if (aList.Count != 0)
            aList = aList.Union(this.GatherAs(aList.SelectMany(a => a.qList)));

        return aList;       
    }

Upvotes: 3

sa_ddam213
sa_ddam213

Reputation: 43596

You should be able to use XDocument to query your xml a bit easier

Example:

  XDocument xdoc = XDocument.Load("c:\\MyXmlFile.xml");
  var results = xdoc.Descendants("a").Descendants("Id").Select(id => id.Value);

Returns all the Id values from a elements.

Upvotes: -1

MarcinJuraszek
MarcinJuraszek

Reputation: 125620

I'm not sure what you're really going to achieve. That's how I understand the problem:

We are looking for <a> tag, that contains another tag named <Id> with value equals to id given as a method parameter. If element is not found method should return null.

I think it can be done on the XML using Descendants() method:

Let say, we have your XML loaded into a variable called doc, which is an instance of XDocument class.

var query= from a in doc.Descendants("a")
           let i = (string)a.Element("Id")
           where i == id
           select a;

return query.FirstOrDefault();

Upvotes: 7

Larry
Larry

Reputation: 18031

Using LINQ to traverse things that references each other looks very hard to achieve to me. It would be easier if the q and a classes were merged together in a single one.

However, as a beginning, your function can be simplified this way :

public a Traverse(List<q> qs, string id)
{
    foreach (var q in qs)
    {
        foreach (var a in q._as)
        {
            if (a.Id == id)
                return a;
            else
                return Traverse(a.qs, id);
        }
    }
    return null;
}

Upvotes: 0

Related Questions