Reputation: 43
I am trying to build a query that select unique groups of values. I know how to group values and select distinct values, but I don't see how to select distinct groups of values regarless of the order of the elements considered. More precisely:
My XML is something like this:
<A>
<B type="1">value1</prop>
<B type="2">value2</prop>
<B type="3">value3</prop>
<B type="4">value4</prop>
<C>
<D>XXX</D>
</C>
<C>
<D>YYY</D>
</C>
</A>
<A>
<B type="3">value3</prop>
<B type="4">value4</prop>
<B type="2">value2</prop>
<C>
<D>XXX</D>
</C>
<C>
<D>YYY</D>
</C>
</A>
Here I would like to make groups of <B>
values from all <A>
nodes and select only unique sets of values. For instance, here:
value1+value2+value3+value4
and
value2+value3+value4+value1
These two sets of values should be only unique if some or all of the values are different.
Thank you very much in advance for your help.
Upvotes: 3
Views: 784
Reputation: 174329
The following works:
var doc = XDocument.Parse(xml);
var comparer = new ElementsComparer();
var result = doc.Descendants("B")
.GroupBy(x => x.Parent)
.Distinct(comparer);
class ElementsComparer : IEqualityComparer<IGrouping<XElement, XElement>>,
IEqualityComparer<XElement>
{
public bool Equals(XElement lhs, XElement rhs)
{
return lhs.Value.Equals(rhs.Value);
}
public bool Equals(IGrouping<XElement, XElement> lhs,
IGrouping<XElement, XElement> rhs)
{
var x = lhs.OrderBy(a => a.Value);
var y = rhs.OrderBy(a => a.Value);
return x.SequenceEqual(y, this);
}
public int GetHashCode(XElement obj)
{
return obj.Value.GetHashCode();
}
public int GetHashCode(IGrouping<XElement, XElement> obj)
{
return 0;
}
}
This returns distinct groups. A group is seen as the same as another group if the elements in the group have the same values as the elements in the other group.
Unfortunatelly, we need a full blown IEqualityComparer
implementation to achieve this.
Upvotes: 2
Reputation: 3297
Try
var xDocument = XDocument.Parse(/*Your XML here*/);
var vals =
//Find all A-Elements
xDocument.Root.Elements("A")
//Select all their B-Elements to one collection
.SelectMany(a => a.Elements("B"))
//Group the B-Items by their value
.GroupBy(element => element.Value)
//Select the keys of the IGrouping<TValue, XElement>
.Select(element => element.Key)
//Distinct them
.Distinct();
Upvotes: 0