使用 Linq 按可选列分组
本文关键字:Linq 使用 | 更新日期: 2023-09-27 18:35:20
我有一个这样的xml:
<LiftFactors>
<Products>
<Product>
<ProductId>Limella</ProductId>
<Tactics>
<Tactic>
<Typ>PriceRed</Typ>
<TPRFrom>0</TPRFrom>
<TprThru>10</TprThru>
<Lift>14</Lift>
<VF>2012-01-09</VF>
<VT>2012-01-11</VT>
</Tactic>
<Tactic>
<Typ>PriceRed</Typ>
<TPRFrom>10 </TPRFrom>
<TprThru>20</TprThru>
<Lift>30</Lift>
<VF>2012-01-07</VF>
<VT>2012-20-08</VT>
</Tactic>
<Tactic>
<Typ>Display</Typ>
<Lift>14</Lift>
<VF>2012-01-04</VF>
<VT>2012-01-06</VT>
</Tactic>
</Tactics>
</Product>
<Product>
<ProductId>Empower Cola</ProductId>
<Tactics>
<Tactic>
<Typ>Display</Typ>
<Lift>20</Lift>
<VF>2012-01-01</VF>
<VT>2012-01-08</VT>
</Tactic>
</Tactics>
</Product>
</Products>
</LiftFactors>
使用以下 linq 语句,我获得了按 ProductId 分组并按 ValidFrom 日期排序的策略数据:
var xml = XElement.Parse(theXML);
var d = (from e in xml.Descendants(@"Product")
group e by e.Element("ProductId").Value into Items
select Items).ToDictionary
(x => x.Key, x => ((XElement)x.First()).Descendants("Tactic").ToList().OrderByDescending (y=> ((DateTime)y.Element("VF"))));
输出:
Limella -> Tactic PriceRed 1
-> Tactic PriceRed 2
-> Tactic Display
Empower Cola -> Tactic Display
现在假设"产品"节点是可选的,我可以在产品节点之外有额外的战术节点:
<LiftFactors>
<Products>
<Product>
<ProductId>Limella</ProductId>
<Tactics>
<Tactic>
<Typ>PriceRed</Typ>
<TPRFrom>0</TPRFrom>
<TprThru>10</TprThru>
<Lift>14</Lift>
<VF>2012-01-09</VF>
<VT>2012-01-11</VT>
</Tactic>
</Tactics>
</Product>
</Products>
<Tactics>
<Tactic>
<Typ>PriceRed</Typ>
<TPRFrom>0</TPRFrom>
<TprThru>10</TprThru>
<Lift>14</Lift>
<VF>2012-01-09</VF>
<VT>2012-01-11</VT>
</Tactic>
</Tactics>
</LiftFactors>
现在我想要的是这个输出:
Limella -> Tactic 1
-> ...
<Null> -> Tactic 2
-> ....
因此,战术也应该出现在没有分配密钥的组中。这是否可能仅使用一个 linq 查询?
试试这个:
var d = xml.Descendants("Tactics")
.GroupBy(e=>e.Parent.Name.LocalName == "Product" ?
e.Parent.Element("ProductId").Value : "")
.ToDictionary(x => x.Key, x => ((XElement)x.First())
.Descendants("Tactic").ToList()
.OrderByDescending (y=>(DateTime)y.Element("VF")));
注意:在Product
外有Tactics
的组有键作为empty string
,您可以稍微更改代码(通过使用 If-else)将其更改为 null
。
以下内容似乎适用于您的示例 XML,这为您提供了一个匿名对象的可枚举集合,如果 Tactic 在产品中,则会填充这些对象的 id 字段,否则为 null:
var xml = XElement.Parse(contents);
var d = xml.Descendants("Tactic").Select(element => element.Parent != null ? new
{
id = element.Parent.Parent.Element("ProductId"),
Tactic = new
{
Typ = element.Descendants("Typ").FirstOrDefault().Value,
TPRFrom = element.Descendants("TPRFrom").FirstOrDefault().Value,
TprThru = element.Descendants("TprThru").FirstOrDefault().Value,
VF = element.Descendants("VF").FirstOrDefault().Value,
VT = element.Descendants("VT").FirstOrDefault().Value
}
} : null);