如何在 Powershell 中从列表中选择和转换项目?

如何在 Powershell 中从列表中选择和转换项目?

我有以下列表:

$list = @('PONTEVEDRA:false:siAPP','MADRID:true:noAPP','MADRID:true:noAPP','PONTEVEDRA:true:siAPP')

我想生成另一个包含以下内容的列表:

$transformedList = @('PONTEVEDRA:1:1:2:0','MADRID:2:1:3:0')

其中 {0} 为地点 {1} 真值总数 {2} 假值总数 {3} siAPP 总数,{4} 为 noAPP 总数,均与其地点相关

我怎样才能在 powershell 中做到这一点?

答案1

我认为群组对象(别名:group) 是此任务的执行 cmdlet。

以下是一种方法:

$SourceList = @('PONTEVEDRA:false','MADRID:true','MADRID:true','PONTEVEDRA:true')
$NewList = $SourceList | ForEach{
    $_ -match '(.+):(.+)' | out-null
    [PSCustomObject]@{
        'Loc' = $matches[1]
        'Bool'= $matches[2]
    }
} | Group Loc -pv loc | ForEach{
    $BoolSplit = $_.Group | Group Bool -NoElement
    '{0}:{1}:{2}' -f $loc.Name,
                     ($BoolSplit | ? Name -eq 'True').Count,
                     ($BoolSplit | ? Name -eq 'False').Count
}

$NewList

编辑:包括摘要信息

如果你分解上面的代码来查看管道中的内容,你会看到以下代码段:

$SourceList | ForEach{
    $_ -match '(.+):(.+)' | out-null
    [PSCustomObject]@{
        'Loc' = $matches[1]
        'Bool'= $matches[2]
    }
}

创建这些对象:

Loc        Bool
---        ----
PONTEVEDRA false
MADRID     true
MADRID     true
PONTEVEDRA true

如果按 分组Bool,将获得“True”和“False”的总计数:

PS > $SourceList | ForEach{
>>     $_ -match '(.+):(.+)' | out-null
>>     [PSCustomObject]@{
>>         'Loc' = $matches[1]
>>         'Bool'= $matches[2]
>>     }
>> } | Group Bool

Count Name                      Group
----- ----                      -----
    1 false                     {@{Loc=PONTEVEDRA; Bool=false}}
    3 true                      {@{Loc=MADRID; Bool=true}, @{Loc=MADRID; Bool=true}, ...

因此,为了捕获中间对象,需要修改原始代码以创建另一个集合。此段:

$NewList = $SourceList | ForEach{
    $_ -match '(.+):(.+)' | out-null
    [PSCustomObject]@{
        'Loc' = $matches[1]
        'Bool'= $matches[2]
    }
}

变成这样:

$NewList = ( $SumList = $SourceList | ForEach{
    $_ -match '(.+):(.+)' | out-null
    [PSCustomObject]@{
        'Loc' = $matches[1]
        'Bool'= $matches[2]
    }
} )

然后,当您运行修改后的代码时,您不仅创建了$NewList,而且$SumList还创建了。这样,您就可以分组并选择:

PS > $sumList | Group Bool -NoElement | select Name, Count

Name  Count
----  -----
false     1
true      3

因此,完整的修改后的代码如下:

$SourceList = @('PONTEVEDRA:false','MADRID:true','MADRID:true','PONTEVEDRA:true')
$NewList = ( $SumList = $SourceList | ForEach{
    $_ -match '(.+):(.+)' | out-null
    [PSCustomObject]@{
        'Loc' = $matches[1]
        'Bool'= $matches[2]
    }
} ) | Group Loc -pv loc | ForEach{
    $BoolSplit = $_.Group | Group Bool -NoElement
    '{0}:{1}:{2}' -f $loc.Name,
                     ($BoolSplit | ? Name -eq 'True').Count,
                     ($BoolSplit | ? Name -eq 'False').Count
}

$NewList

$sumList | Group Bool -NoElement | select Name, Count

编辑3:替代摘要方法:

如果您需要进一步访问对象形式的原始数据,上述方法会很好,但如果您只需要上述总和,则下面的方法可能更有效、更快捷。它不会创建另一个集合或列表,而是使用引用变量来在处理数据时保持总数:

$SourceList = @('PONTEVEDRA:false','MADRID:true','MADRID:true','PONTEVEDRA:true')

[ref]$TrueTotal  = 0
[ref]$FalseTotal = 0

$NewList = $SourceList | ForEach{
    $_ -match '(.+):(.+)' | out-null
    [PSCustomObject]@{
        'Loc' = $matches[1]
        'Bool'= $matches[2]
    }
} | Group Loc -pv loc | ForEach{
    $BoolSplit = $_.Group | Group Bool -NoElement
    '{0}:{1}:{2}' -f $loc.Name,
                     ($TrueCount  = ($BoolSplit | ? Name -eq 'True').Count),
                     ($FalseCount = ($BoolSplit | ? Name -eq 'False').Count)
    $TrueTotal.Value  += $TrueCount
    $FalseTotal.Value += $FalseCount
}

$NewList
'Total "True"  : {0}' -f $TrueTotal.Value
'Total "False" : {0}' -f $FalseTotal.Value`



编辑#2:附加数据

与之前一样,您要做的第一件事是将数据转换为对象。这次我采取了略有不同的策略——不是为了混淆,而是为了展示另一种方法。如果您的数据实际上来自文件,您可以使用Import-Csv而不是ConvertFrom-Csv

$list = @('PONTEVEDRA:false:siAPP','MADRID:true:noAPP','MADRID:true:noAPP','PONTEVEDRA:true:siAPP')

$ListObjects = $List | ConvertFrom-Csv -Delimiter ':' -Header ('Loc','locBool','AppInfo')

得出的结果是:

PS > $ListObjects

Loc        locBool AppInfo
---        ------- -------
PONTEVEDRA false   siAPP
MADRID     true    noAPP
MADRID     true    noAPP
PONTEVEDRA true    siAPP

再次,分组**Loc**

PS > $ListObjects | group Loc

Count Name                      Group
----- ----                      -----
    2 PONTEVEDRA                {@{Loc=PONTEVEDRA; locBool=false; AppInfo=siAPP; Count=2; Na...
    2 MADRID                    {@{Loc=MADRID; locBool=true; AppInfo=noAPP; Count=2; Name=MA...

并且Group 财产我们可以使用以下方法提取所需的数据:Where 方法可供收藏:

$ListObjects | Group Loc | %{
    $BoolGroup = $_.Group | Group locBool -NoElement
    $AppGroup  = $_.Group | Group AppInfo -NoElement
    '{0}:{1}:{2}:{3}:{4}' -f $_.Name ,
                             $BoolGroup.Where{$_.Name -match 'true'}[0].Count ,
                             $BoolGroup.Where{$_.Name -match 'false'}[0].Count ,
                             $AppGroup.Where{$_.Name -match 'siAPP'}[0].Count ,
                             $AppGroup.Where{$_.Name -match 'noApp'}[0].Count
}

输出:

PS > $ListObjects | Group Loc | %{
>>     $BoolGroup = $_.Group | Group locBool -NoElement
>>     $AppGroup  = $_.Group | Group AppInfo -NoElement
>>     '{0}:{1}:{2}:{3}:{4}' -f $_.Name ,
>>                              $BoolGroup.Where{$_.Name -match 'true'}[0].Count ,
>>                              $BoolGroup.Where{$_.Name -match 'false'}[0].Count ,
>>                              $AppGroup.Where{$_.Name -match 'siAPP'}[0].Count ,
>>                              $AppGroup.Where{$_.Name -match 'noApp'}[0].Count
>> }
>>
PONTEVEDRA:1:1:2:0
MADRID:2:0:0:2
PS >

请注意,由于该Where()方法即使有零个或一个元素也会返回一个集合 -- 并且集合具有Count自己的属性,因此您必须指定数组索引才能从和子组中[0]获取。如果没有这个,将只返回或-- 取决于指定分组中是否有任何元素。CountBoolGroupAppGroupCount01

相关内容