问题
I am trying to get a distinct list of elements but it always returns everything.
Xml:
<root>
<row>
<unit>CAN</unit>
</row>
<row>
<unit>KG</unit>
</row>
<row>
<unit>KG</unit>
</row>
<row>
<unit>PKT</unit>
</row>
<row>
<unit>CAN</unit>
</row>
<row>
<unit>PKT</unit>
</row>
<row>
<unit>KG</unit>
</row>
</root>
Linq:
List<XElement> elements = (from e in xdoc.Descendants("row").Elements()
where e.Name.Equals("unit")
select e).Distinct().ToList();
Expected output: elements list should contain 3 items
<unit>CAN</unit>
<unit>KG</unit>
<unit>PKT</unit>
回答1:
Distinct()
does not know what part of the XElement
to compare, so it will just compare the object reference. Since all XElements are separate objects, no matter the content, it will return them all.
You either have to define an IEqualityComparer that allows it to compare them (probably the preferred way to do it) or just use GroupBy that can take a lambda that will allow it to compare the actual Value instead;
var elements = (from e in xdoc.Root.Elements("row").Elements("unit")
select e).GroupBy(x => x.Value).Select(x => x.First());
Output:
<unit>CAN</unit>
<unit>KG</unit>
<unit>PKT</unit>
回答2:
select e.Value,
from e in xdoc.Descendants("row").Elements()
where e.Name.Equals("unit")
select e.Value).Distinct().ToList();
回答3:
I would group and take the first item in each group:
XDocument doc = XDocument.Load("../../XMLFile1.xml");
List<XElement> distinctUnits =
(from unit in doc.Root.Elements("row").Elements("unit")
group unit by (string)unit into g
select g.First()).ToList();
foreach (XElement unit in distinctUnits)
{
Console.WriteLine(unit);
}
回答4:
this will get the result
List<XElement> elements = new List<XElement>();
foreach (var item in xdoc.Descendants().Where(c => c.Name == "unit").Select(c=>c))
{
if (elements.Where(c => c.Value == item.Value).FirstOrDefault() == null)
{
elements.Add(item);
}
}
<unit>CAN</unit>
<unit>KG</unit>
<unit>PKT</unit>
回答5:
This works for me:
var query = (from e in xml.Root.Elements("row").Elements("unit")
select e).GroupBy(e => e.Value).Select(x => x.First());
EDIT: Whoops-- I overlooked the 'distinct' requirement. Amending the above answer using Joachim Isaksson's lambda expression. Here's the new output:
<unit>CAN</unit>
<unit>KG</unit>
<unit>PKT</unit>
来源:https://stackoverflow.com/questions/12097185/xdocument-select-distinct-elements-using-linq