1

我有一个测试输入csv文件,如下:

ID;Product;Price;Discount;Level
1;Alpha;23.00;0.03;A
2;Bravo;17.00;0.01;A
3;Charlie;11.00;0.05;A
4;Delta;17.00;0.05;A
5;Echo;29.00;0.07;A
6;Foxtrot;11.00;0.01;A
7;Golf;11.00;0.01;A
1;Hotel;53.00;0.11;B
2;India;53.00;0.13;B
3;Juliet;61.00;0.11;B
1;Kilo;79.00;0.23;C
2;Lima;89.00;0.23;C
3;Mike;97.00;0.29;C
4;November;83.00;0.17;C
5;Oscar;79.00;0.11;C

我想生成以下输出文件:

ID;Product;Price;Discount;Level
1;Alpha;23.00;0.03;A
5;Echo;29.00;0.07;A
2;India;53.00;0.13;B
3;Juliet;61.00;0.11;B
2;Lima;89.00;0.23;C
3;Mike;97.00;0.29;C

也就是说,对于每个级别,我想选择按价格排序的前两行,然后是折扣。例如,对于 level B,我想要JulietIndia不是Julietand Hotel

我有以下代码片段并不能完全交付!

$input = '.\TestInput.csv'
$products = @(Import-CSV -Path $input -Delimiter ";")
$levels = $products | 
    Group-Object -Property Level -AsHashTable 

$sales = $levels.GetEnumerator() | 
    Sort-Object -Property @{ Expression = { [int]($_.Price) } ; Descending = $true },
                          @{ Expression = { [int]($_.Discount) } ; Descending = $true } | 
    Select-Object -first 2

$output = '.\TestOutput.csv'
$sales | Export-Csv -Path $output -Delimiter ";" -NoTypeInformation

我错过了什么?

4

2 回答 2

3
$sales = ForEach ($Level in $levels.Keys | Sort-Object) { $levels.$Level | Sort-Object -Property  price,discount | Select-Object -last 2 }
于 2020-06-30T10:46:38.800 回答
2

Group-Object直接在Import-Csv输出上使用:

Import-Csv '.\TestInput.csv' -Delimiter ';' | 
  Group-Object Level | 
    ForEach-Object { 
      $_.Group |
        Sort-Object { [int] $_.Price }, { [int] $_.Discount } |
          Select-Object -Last 2
    } | 
        Export-Csv -Path '.\TestOutput.csv' -Delimiter ";" -NoTypeInformation

注意:在 PowerShell [Core] v6+ 中,您可以替换| Select-Object Last 2-Bottom 2,因为Sort-Object现在支持-Top-Bottom参数。


至于你尝试了什么:

  • 虽然Group-Object通常按指定的分组标准(Level在本例中为 )对结果组进行排序,但如果您使用 ,则不再保证这种排序-AsHashtable,因为哈希表条目本质上是无序的。

    • 为了防止这种情况发生,要么使用默认输出(no -AsHashtable)——它产生单独的组对象——如上所示,要么添加一个Sort-Object按 排序的最终调用Level
  • $levels.GetEnumerator()通过管道发送键值System.Collections.DictionaryEntry实例),其.Key属性为分组标准(.Level),其.Value属性为关联组。

    • 但是,您应该只通过管道发送条目 (即组对象),而不是键值对;这可以通过简单地访问哈希表的.Values属性 来实现
      • 但是,由于您需要单独处理每个组,要找到每个组中的最大值,您需要一个中间ForEach-Object调用,在其中执行特定于组的处理。
  • 您正在使用计算属性(基于哈希表的动态属性定义)来指定Sort-Object; 但是,Sort-Object永远不需要这样做,因为您永远不会看到此类属性的名称因此,直接使用上面的表达式脚本块(如图所示)就足够了。

  • 由于您的排序是按降序排列的,Select-Object -First 2因此将显示两个最高值,但按降序排列,而您所需的输出要求它们按升序排列

    • 要获得后者,请按升序排序,然后选择最后2 个对象。

将它们放在一起(但请注意,顶部的解决方案在概念上更简单且更有效):

$sales = 
  $levels.Values | ForEach-Object { 
      $_ |  # process the group at hand
        Sort-Object -Property { [int] $_.Price }, { [int] $_.Discount } | 
          Select-Object -Last 2
    } | Sort-Object Level
于 2020-06-30T11:13:30.860 回答