Home > Net >  How can I find matching string name in the same object and then add value that is contain on each of
How can I find matching string name in the same object and then add value that is contain on each of

Time:10-19

I created a powershell command to collect and sort a txt file.

Input example:

a,1  
a,1  
b,3  
c,4  
z,5  

The output that I have to get:

a,2  
b,3  
c,4  
z,5  

Here is my code so far:

$filename = 'test.txt'
Get-Content $filename | ForEach-Object {
    $Line = $_.Trim() -Split ','
    New-Object -TypeName PSCustomObject -Property @{
        Alphabet= $Line[0]
        Value= [int]$Line[1]
    }
}

example with negative value input

a,1,1
a,1,2
b,3,1
c,4,1
z,5,0

CodePudding user response:

  • Import your text file as a CSV file using Import-Csv with given column names (-Header), which parses the lines into objects with the column names as property names.

  • Then use Group-Object to group the objects by shared .Letter values, i.e. the letter that is in the first field of each line.

  • Using ForEach-Object, process each group of objects (lines), and output a single string that contains the shared letter and the sum of all .Number property values across the objects that make up the group, obtained via Measure-Object -Sum:

@'
a,1
a,1
b,3
c,4
z,5
'@ > ./test.txt

Import-Csv -Header Letter, Number test.txt |
  Group-Object Letter |
  ForEach-Object {
    '{0},{1}' -f $_.Name, ($_.Group | Measure-Object -Sum -Property Number ).Sum
  }

Note: The above OOP approach is flexible, but potentially slow. Here's a plain-text alternative that will likely perform better:

Get-Content test.txt |
  Group-Object { ($_ -split ',')[0] } |
  ForEach-Object {
    '{0},{1}' -f $_.Name, ($_.Group -replace '^. ,' | Measure-Object -Sum).Sum
  }

See also:


Grouping with summing of multiple fields:

It is easy to extend the OOP approach: add another header field to name the additional column, and add another output field that sums that added column's values for each group too:

@'
a,1,10
a,1,10
b,3,30
'@ > ./test.txt

Import-Csv -Header Letter, NumberA, NumberB test.txt |
  Group-Object Letter |
  ForEach-Object {
    '{0},{1},{2}' -f $_.Name, 
                  ($_.Group | Measure-Object -Sum -Property NumberA).Sum, 
                  ($_.Group | Measure-Object -Sum -Property NumberB).Sum
  }

Output (note the values in the a line):

a,2,20
b,3,30

Extending the plain-text approach requires a bit more work:

@'
a,1,10
a,1,10
b,3,30
c,4,40
z,5,50
'@ > ./test.txt

Get-Content test.txt |
  Group-Object { ($_ -split ',')[0] } |
  ForEach-Object {
    '{0},{1},{2}' -f $_.Name, 
                  ($_.Group.ForEach({ ($_ -split ',')[1] }) | Measure-Object -Sum).Sum, 
                  ($_.Group.ForEach({ ($_ -split ',')[2] }) | Measure-Object -Sum).Sum
  }

CodePudding user response:

One way to go about this is using Group-Object for the count, and then replacing the current number after the comma with the count.

$filename = 'test.txt'
Get-Content $filename | Group-Object | 
    ForEach-Object -Process {
        if ($_.Count -ne 1) { 
            $_.Name -replace '\d',$_.Count 
        }
        else { 
            $_.Name 
        }    
}  | ConvertFrom-Csv -Header 'Alphabet','Value'
  • Related