What is the LINQ to XML equivalent for this XPath - c#

I wondering what the "best practice" way (in C#) is to implement this xpath query with LINQ:
/topNode/middleNode[#filteringAttribute='filterValue']/penultimateNode[#anotherFilterAttribute='somethingElse']/nodesIWantReturned
I would like an IEnumerable list of the 'nodesIWantReturned', but only from a certain section of the XML tree, dependent on the value of ancestor attributes.

In addition to the Linq methods shown, you can also import the System.Xml.XPath namespace and then use the XPathSelectElements extension method to use your XPath query directly.
It is noted in the class that these methods are slower than 'proper' Linq-to-XML, however a lot of the time this isn't too important, and sometimes it's easier just to use XPath (it's certainly a lot terser!).
var result = doc.XPathSelectElements("your xpath here");

var result = root.Elements("topNode")
.Elements("middleNode")
.Where(a => (string)a.Attribute("filteringAttribute") == "filterValue")
.Elements("penultimateNode")
.Where(a => (string)a.Attribute("anotherFilterAttribute") == "somethingElse")
.Elements("nodesIWantReturned");

A more verbal solution:
var nodesIWantReturned = from m in doc.Elements("topNode").Elements("middleNode")
from p in m.Elements("penultimateNode")
from n in p.Elements("nodesIWantReturned")
where m.Attribute("filteringAttribute").Value == "filterValue"
where p.Attribute("anotherFilterAttribute").Value == "somethingElse"
select n;

Related

Set several class values using LINQ expression

I have the following two LINQ statements which set different values in the same item in a list
List<MyClass> myList = GetList();
myList.Where(x => x.Name == "someName").Select(x => x.MyArray = someList.ToArray()).ToList();
myList.Where(x => x.Name == "someName").Select( x => x.AnotherValue = GetValue()).ToList();
Is it possible to combine this so both are set in the one expression?
myList
.Where(x => x.Name == "someName")
.ToList()
.ForEach(x => {
x.MyArray = someList.ToArray();
x.AnotherValue = GetValue();
});
Why are you calling ToList() at the end of each of those expressions and discarding the result?
Also, Jon Skeet is right that this is an abuse of LINQ, and especially so in your original form: It's explicit that LINQ expressions aren't even necessarily expected to be fully enumerated. The fact that you needed those ToList() calls to make anything happen should have given you a grave and queasy sense that you were misusing a language feature. When you have to do something weird to use your chosen construct instead of the usual way of doing it, finish getting it to work (because weird is cool), and then go back and redo it the boring, lame way before you check it in.
What advantage do you see in the LINQ + ForEach() version above, compared to this version?
foreach (var x in myList.Where(x => x.Name == "someName"))
{
x.MyArray = someList.ToArray();
x.AnotherValue = GetValue();
}
The old-style loop version is shorter, instantly understandable because it's the default idiom, and IMO cleaner. You don't have to do everything with LINQ.
N.B., ForEach() isn't LINQ; it's a member of List<T>. That's why you have to call ToList() to use it.
Just use the lambda operator to pass an entire lambda expression defined inside a
{...} block:
myList.Where(x => x.Name == "someName").Select(x => { x.MyArray = someList.ToArray(); x.AnotherValue = GetValue(); return x;}).ToList();

method syntax for linq query with multiple from clauses

I was trying to figure out how to replace the nested from clause to a method syntax. I was trying with .Select or .SelectMany, but I didn't manage to get the same result.
var query = (from DirectToStoreStore s in dtsOrder.Stores
from DirectToStoreProduct p in s.Products
where p.DirectToStoreOrderLineID == directToOrderLineID
select p);
There's plenty of ways you could write it.
var query = dtsOrder.Stores.Cast<DirectToStoreStore>()
.SelectMany(s => s.Products.Cast<DirectToStoreProduct>()
.Where(p => p.DirectToStoreOrderLineID == directToOrderLineID)
);
Though the casts may not be necessary, but they're only there since you explicitly declared them in your query. It'll probably be safe to remove them.

C# and LINQ - arbitrary statement instead of let

Let's say I'm doing a LINQ query like this (this is LINQ to Objects, BTW):
var rows =
from t in totals
let name = Utilities.GetName(t)
orderby name
select t;
So the GetName method just calculates a display name from a Total object and is a decent use of the let keyword. But let's say I have another method, Utilities.Sum() that applies some math on a Total object and sets some properties on it. I can use let to achieve this, like so:
var rows =
from t in totals
let unused = Utilities.Sum(t)
select t;
The thing that is weird here, is that Utilities.Sum() has to return a value, even if I don't use it. Is there a way to use it inside a LINQ statement if it returns void? I obviously can't do something like this:
var rows =
from t in totals
Utilities.Sum(t)
select t;
PS - I know this is probably not good practice to call a method with side effects in a LINQ expression. Just trying to understand LINQ syntax completely.
No, there is no LINQ method that performs an Action on all of the items in the IEnumerable<T>. It was very specifically left out because the designers actively didn't want it to be in there.
Answering the question
No, but you could cheat by creating a Func which just calls the intended method and spits out a random return value, bool for example:
Func<Total, bool> dummy = (total) =>
{
Utilities.Sum(total);
return true;
};
var rows = from t in totals
let unused = dummy(t)
select t;
But this is not a good idea - it's not particularly readable.
The let statement behind the scenes
What the above query will translate to is something similar to this:
var rows = totals.Select(t => new { t, unused = dummy(t) })
.Select(x => x.t);
So another option if you want to use method-syntax instead of query-syntax, what you could do is:
var rows = totals.Select(t =>
{
Utilities.Sum(t);
return t;
});
A little better, but still abusing LINQ.
... but what you should do
But I really see no reason not to just simply loop around totals separately:
foreach (var t in totals)
Utilities.Sum(t);
You should download the "Interactive Extensions" (NuGet Ix-Main) from Microsoft's Reactive Extensions team. It has a load of useful extensions. It'll let you do this:
var rows =
from t in totals.Do(x => Utilities.Sum(x))
select t;
It's there to allow side-effects on a traversed enumerable.
Please, read my comment to the question. The simplest way to achieve such of functionality is to use query like this:
var rows = from t in totals
group t by t.name into grp
select new
{
Name = t.Key,
Sum = grp.Sum()
};
Above query returns IEnumerable object.
For further information, please see: 101 LINQ Samples

How can i convert this code snippet into LINQ format?

foreach (var invitation in PendingContactList.CollectionContent)
{
if (!invitation.Contact.incoming)
{
contactInvitationsSent.Add(invitation);
}
}
PendingContactList is a list.
Something like that if contactInvitationsSent is List<T>:
contactInvitationsSent.AddRange(
PendingContactList.CollectionContent.Where(item => !item.Contact.incoming)
);
In case of contactInvitationsSent is not a List<T> and we don't have AddRange method we have to use Add, it seem that Linq is of little help in that case:
foreach(var invitation in PendingContactList.CollectionContent
.Where(item => !item.Contact.incoming))
contactInvitationsSent.Add(invitation);
You can use the following, although it is not guarranteed to give you any performance boost.
contactInvitationSent.AddRange(PendingContactList.CollectionContent
.Where(i => !i.Contact.incoming);
Just for you information, you can also install plugins like ReSharper.
And yes, the price and performance of the tool just does not always compensate for the features it provides. However, questions like thise one can be avoided :-)
There are also some free alternative available. For example the power tools.
http://visualstudiogallery.msdn.microsoft.com/3a96a4dc-ba9c-4589-92c5-640e07332afd
Just read more about resharper etc, goodluck!
try something like :
contactInvitationsSent = PendingContactList.CollectionContent
.Where(x => x.Contact.incoming == false)
.Select(x => x).ToList();
Linq is awesome and very simple notation.
You have to use following syntax.
var demo = (from n in PendingContactList.CollectionContent where n.incoming==false select n).ToList();

Location of XElement when querying over IEnumerable using LINQ

I have a linq query that is querying over IEnumberable. When I have a matching element for my where clause I would like to know the position of the element in the IEnumberable.
var result = from e in elements
where (string) e.Attribute("class") == "something"
select e.Position();
The e.Position() of course does not compile. The value of e.Position() would be the position of the selected element in the elements IEnumberable.
Any ideas on how to do this?
You need to use the overloaded Select method that allows for an index since that capability is not available in query syntax.
elements.Select((e, i) => new { Element = e, Index = i })
.Where(item => (string)item.Element.Attribute("class") == "something")
.Select(item => item.Index);
If you're using .NET 4.0 then you can use the (new) Zip method and write the same thing using the query syntax as well. It creates some temporary objects, so it isn't as efficient, but some people may find it more readable:
var result = from e in elements.Zip
(Enumerable.Range(0, elements.Count()), Tuple.Create)
where (string)e.Item1.Attribute("class") == "something"
select e.Item2;
It 'zips' the input collection with a generated sequence of numbers (with the same range as is the length of the collection). Then you can store the combined value either using the Tuple class (that's what I did) or you could use anonymous type.

Categories

Resources