我有以下函数来生成输出屏幕截图中显示的表格。我想修改这个函数以获得如下所示的所需输出,但我对 C# 不太熟悉。如果我将years数组传递到这个由3项组成的函数中,我应该如何修改这个函数?
private string GenerateHTML(string year)
{
var regions = RegionalList(year);
if (!regions.Any()) return "";
var rowHtmlString = regions.OrderByDescending(row => row.Capacity).Aggregate("", (current, row) => current + $@"
<tr>
<td>
<p>{row.Region}</p>
</td>
<td>
<p>{row.Percent.ToString("F1")}%</p>
</td>
</tr>
");
return rowHtmlString;
}
所以你的方法
RegionalList
是一个输入字符串Year,并输出一系列Regions的方法。显然,每个区域都有一个描述性 Name
(北、东等)和一个值 Capacity
。像这样的东西:
class Region
{
public string Name {get; set;} // may be enum
public decimal Capacity {get; set;}
... // other properties
}
IEnumerable<Region> GetRegions(string year) {...} // Formerly known as ListRegions
如果您只有一年的时间,您已经找到了创建 HTML 的方法。现在您有一个年份的输入序列,并且您希望输出为
Region Names with per year the capacity
,如下所示:
class YearCapacity
{
public int Year {get; set;}
public decimal Capacity {get; set;}
}
class RegionWithItsYearCapacities
{
public string RegionName {get; set;}
public ICollection<YearCapacity> YearCapacities {get; set;}
}
一旦您获得了区域序列及其 YearCapacities,我想您知道如何将其转换为正确的 HTML。我的建议是单独进行此转换,因此如果以后您想要转换为 XML、JSON 或任何其他格式,则无需更改原始 LINQ。
所以我假设您有以下内容:
// converts one Region with its year capacities into HTML:
static string ToHtml(this RegionWithItsYearCapacities regionWithItsYearCapacities)
{
... // TODO: implement. Outside of this question
}
我为此使用了扩展方法。如果您不熟悉扩展方法,请考虑阅读[扩展方法揭秘][1]
以及将序列转换为 HTML 的扩展方法:
static <string ToHtml (
this IEnumerable<RegionWithItsYearCapacities> regionsWithTheirYearCapacities)
{
// if needed add preliminary HTML
string result = ...
// add HTML for each region with its own YearCapacities
foreach (var region in regionsWithTheirYearCapacities)
{
result += region.ToHtml();
}
// if needed add some post HTML:
result += ...
return string;
}
我之所以使用这种方法,是因为我不确定仅具有有关区域及其年份容量的重复信息序列是否是好的 HTML。也许您想添加一些初步/后期信息。 (嗯,真正的原因是我不确定 HTML 格式是否正确)
好的,这是代码:
IEnumerable<string> years = ...
IEnumerable<Region> yearWithRegions = years.Select(year => new
{
Year = year,
Regions = GetRegions(year),
});
现在您已经有了一个年份序列,并且每年都有今年的所有区域,如下所示:
2022:
North: 8.9%
East: 36.8%
South: 10.4%
West: 18.5%
2021:
North: 8.0%
East: 0.8%
South: 0.4%
West: 18.5%
2020:
etc.
我们将把这个序列压平成
Year - Region - Capacity
的序列,然后制作区域组,每个区域都有它的Year - Capacity
。
展平是使用 [Enumerable.SelectMany][2] 的重载之一完成的。分组是使用 [Enumerable.GroupBy][3]
完成的var RegionsWithTheirYearCapacities = yearWithRegions // see intermediate result above
// Flatten:
.SelectMany(yearWithRegion => yearWithRegion.Name,
yearWithRegion => yearWithRegion.Regions, // the collection to flatten
// parameter Result Selector: from every year and Region-Capacity combination
// make one new:
(year, regionCapacityCombination) => new
{
Year = year,
Region = regionCapacityCombination.Name,
Capacity = regionCapacityCombination.Capacity),
})
等等,还没完,我只是想展示一下我们现在所拥有的:
2022 - North - 8.9%
2022 - East - 36.8%
2022 - South - 10.4%
2022 - West - 18.5%
2021 - North - 8.0%
2021 - East - 0.8%
2021 - South - 0.4%
2021 - West - 18.5%
2020 - ... etc
好的,继续 LINQ,创建具有相同区域值的年份 - 区域 - 容量组合组:
.GroupBy(yearRegionCapacityCombination => yearRegionCapacityCombination.Region
// parameter resultSelector: for every found Regions, with all combinations
// that have this Region, make one new:
(region, combinationsWithThisRegion) => new RegionWithItsYearCapacities
{
Region = region,
YearCapacities = combinationsWithThisRegion.Select(combination => new YearCapacity
{
Year = combination.Year,
Capacity = combination.Capacity,
})
.ToList(),
})
中间结果:
North:
2022: 8.9%
2021: 8.0%
2020: ...
East:
2022: 36.8%
2021: 0.8%
2020: ...
South: ... etc
快到了,我们所要做的就是将其转换为 HTML 序列:
.ToHtml();
为了让您清楚地了解发生了什么,我将 LINQ 剪成了更小的部分。当然,您可以将所有这些都放在一个大的 LINQ 中。这不会改变效率。但我确信它会降低可读性、重用性、可更改性和单元测试的可能性。 [1]: https://www.dotnetcurry.com/csharp/995/extension-methods-csharp#:~:text=Extension%20methods%20allow%20you%20to,直接修改%20这些%20existing%20types%20 。 [2]:https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.selectmany?view=net-8.0 [3]:https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.groupby?view=net-8.0