简体   繁体   中英

Filtering within a Group - Group-Object

Background info:
Each Element has an IndicatorType of either '10' or 'ND'
Indicator has values of either '!' , '' (empty string/null), 'o', 'u'

Question:
I need to filter data in each "Element" group based on this pseudo code rule and then export the result to file:
For Each "Element" Group if Indicator='!' or '' for BOTH IndicatorTypes(ie '10','ND'), Select group where indicatorType=ND
ELSE if Indicator='!' or '' for IndicatorType = 10 and Indicator='o' or 'u' for IndicatorType=ND Select group where indicatorType=10

My Source file:

"Code","IndicatorType","Indicator","Element","Data"
"111","10","","S","0.039"
"111","10","!","Cr ","0.045"
"111","10","","Zn","0.011"
"111","10","!","P","0.013"
"111","10","","Ni ","56.480"
"111","10","!","Co ","1.081"
"111","10","!","Fe","45.655"
"111","10","!","Si","0.364"
"111","10","!","Mn","0.005"
"111","10","!","Al","0.007"
"111","10","!","Cu","0.014"
"111","10","!","Y","0.00"
"111","ND","","S","0.037"
"111","ND","","Cr ","0.039"
"111","ND","","Zn","0.010"
"111","ND","","P","0.013"
"111","ND","o","Ni ","37.107"
"111","ND","o","Co ","0.887"
"111","ND","o","Fe","37.430"
"111","ND","","Si","0.348"
"111","ND","","Mn","0.005"
"111","ND","","Al","0.008"
"111","ND","","Cu","0.013"
"111","ND","","Y","0.00"

My code grouping by Element :

$myfile = Get-ChildItem -Path $myfileSource *.csv
$myfileData = Import-Csv $myfile.FullName | Group-Object Element | 
              Where-Object -FilterScript {($_.Group.IndicatorType -eq 'ND' -and
                                          $_.Group.Indicator -eq '!' -or 
                                          $_.Group.Indicator -eq '') -or
                                          ($_.Group.IndicatorType -eq '10' -and
                                          $_.Group.Indicator -eq 'o' -or 
                                          $_.Group.Indicator -eq 'u' -or 
                                          $_.Group.Indicator -eq '!' -or
                                          $_.Group.Indicator -eq '')  
                                         }| Export-Csv -Path $myFile.FullName -Force -NoTypeInformation

PROBEM:
The problem is with my Where-Object, it returns all the values.
How can I apply the pseudo code rule to my Where-Object to only select the desired group? 在此处输入图片说明

$_.Group will return both objects for the same element, so your tests will filter the list (ex. IndicatorType for both objects in the group) using the value on the right side of -eq , and the condition will most likely be true. Ex:

$_.Group.IndicatorType -eq 'ND'
#Translates to array of "IndicatorTypes in the group" -eq 'ND'
10,'ND' -eq 'ND'
#The line above filters the array on the left to show matching values, this returns
'ND'
#A value is always true, so this test will be
$true

You solve this by finding the objects in the group you want to perform the tests on first.

Also, using Group-Object Element | Where-Object … Group-Object Element | Where-Object … means that if the where-clause is true, you will keep the whole object returned from Group-Object (containing Count, Name and the elements-group). You should use Foreach-Object instead since you only want to keep one object per approved element-group. Try:

$myfile = Get-ChildItem -Path $myfileSource *.csv

$myfileData = Import-Csv $myfile.FullName | 
#For Each "Element" Group
Group-Object Element | Foreach-Object {
    $Ten = $_.Group | Where-Object { $_.IndicatorType -eq '10' }
    $ND = $_.Group | Where-Object { $_.IndicatorType -eq 'ND' }

    if(('!','' -contains $Ten.Indicator) -and ('!','' -contains $ND.Indicator)) {
        #if Indicator='!' or '' for BOTH IndicatorTypes(ie '10','ND'), Select group where indicatorType=ND
        $ND
    } elseif (('!','' -contains $Ten.Indicator) -and ('o','u' -contains $ND.Indicator)) {
        #ELSE if Indicator='!' or '' for IndicatorType = 10 and Indicator='o' or 'u' for IndicatorType=ND Select group where indicatorType=10
        $Ten
    }
} | Export-Csv -Path $myFile.FullName -Force -NoTypeInformation

Group-Object returns a collection of GroupInfo objects each of which contains a collection of the elements in the group - essentially a list of lists. Running the cmdlet produces (based on the example input) a list of 12 groups:

PS[1] (191) > $data = import-csv  data2.txt | group-object element
PS[1] (192) > $data.Count
12

Looking at the first item returned:

PS[1] > $data[0].Group.Count
2

You can see that it contains two entries which look like:

PS[1] (193) > $data[0].Group

Code          : 111
IndicatorType : 10
Indicator     :
Element       : S
Data          : 0.039

Code          : 111
IndicatorType : ND
Indicator     :
Element       : S
Data          : 0.037

This means that your selection criteria will have to be applied to each/all of the entries in the collection of data associated with the group to decide if you want to return that group. In your example code, you appear to be assuming that a group is flat which it's not.Unfortunately I don't entirely understand what you are trying to do so I can't provide a complete answer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM