I've been working on something with alot of iteration (foreach) and now that everything is working I'd like to optimize it by changing it to link. Currently I am trying to translate this foreach code to LINQ

int count = 0;
foreach( string file in Directory.GetFiles( path ))
{
        XDocument xdoc = new XDocument();
        xdoc = XDocument.Load( file );
         count += xdoc.Descendants( "PAGE" ).Count();
}

I'm not sure if it even possible however, here is the result of my trying :)

int count;
count = Directory.GetFiles( path ).Select( file => XDocument.Load( file ).Descendants( "PAGE" )).Select( result => result).Count() ;

I'd appreciate if someone could help but also explain me what's going on with the LINQ query.

Thank you =)

The first part of the query is retrieving the files in the given directory. The second part is a select projection that takes a given filename, loads an XDocument and retrieves all descendants of that document of a particular name. In terms of the delegate signature for the inner function, it would be

Func<string, IEnumerable<XElement>> func

As in a function that takes a string (file) and returns an IEnumerable of XElements.

Next, you're including what is currently an unnecessary Select call that simply takes an IEnumerable<XElement> and returns the same IEnumerable<XElement>.

Func<IEnumerable<XElement>, IEnumerable<XElement>> func

And, lastly, you're retrieving the count of all elements in the IEnumerable<IEnumerable<XElement>>. But what you're getting is actually a count of the inner IEnumerable<XElement> elements, not the count of the XElements.

To get the total count of your descendants, you could rewrite the statement to look something like this:

int sum = Directory.GetFiles(directoryPath)
            .Select(file => XDocument.Load(file).Descendants(descendantName).Count())
            .Sum();

Edit: Since I spelled out the other select functions, this one is taking a sting filename and returning an integer representing the count of descendants of a given name in the file.

Func<string,int>

And then, of course, you simply sum those integer results.

The first part of the query is retrieving the files in the given directory. The second part is a select projection that takes a given filename, loads an XDocument and retrieves all descendants of that document of a particular name. In terms of the delegate signature for the inner function, it would be

Func<string, IEnumerable<XElement>> func

As in a function that takes a string (file) and returns an IEnumerable of XElements.

Next, you're including what is currently an unnecessary Select call that simply takes an IEnumerable<XElement> and returns the same IEnumerable<XElement>.

Func<IEnumerable<XElement>, IEnumerable<XElement>> func

And, lastly, you're retrieving the count of all elements in the IEnumerable<IEnumerable<XElement>>. But what you're getting is actually a count of the inner IEnumerable<XElement> elements, not the count of the XElements.

To get the total count of your descendants, you could rewrite the statement to look something like this:

int sum = Directory.GetFiles(directoryPath)
            .Select(file => XDocument.Load(file).Descendants(descendantName).Count())
            .Sum();

Of course it makes sens, I realise that if I had written this with an SQL query it would have ended up this way. What I am not understanding is that I didn't think about that :) Anyways, you are awesome man, thank you for your help with LINQ, really appreciated.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.