2

What is the easy and efficient way to transform an array using PowerShell? An initial array has two properties Number and Color.

Number  Color
1       Red
2       Red
3       Red
4       Red
5       Blue
6       Blue
7       Green
8       Green
9       Green

An output array should like:

Color   Number
Red     1,2,3,4
Blue    5,6
Green   7,8,9
2
  • 2
    Have you looked at Group-Object? That's a pretty common cmdlet for exactly this purpose. Also, why would 5 and 6 be grouped under both Red and Blue in the output? Commented Apr 28, 2020 at 22:09
  • I couldn't get the needed output using Group-Object. it's an error - 5,6 should be in blue only. Commented Apr 28, 2020 at 22:25

2 Answers 2

4
# Input objects.
$objects = @'
Number,Color
1,Red
2,Red
3,Red
4,Red
5,Blue
6,Blue
7,Green
8,Green
9,Green
'@ | ConvertFrom-Csv

$objects |
  Group-Object Color |
  Select-Object @{ n='Color'; e='Name'}, @{ n='Number'; e={ $_.Group.Number } }

The above yields:

Color Number
----- ------
Blue  {5, 6}
Green {7, 8, 9}
Red   {1, 2, 3, 4}

Note: Due to how Group-Object works, the Color values are sorted alphabetically in the output.

See also:

Sign up to request clarification or add additional context in comments.

Comments

1

Adding to @mklement0's great answer using Group-Object, we can also group the items into a System.Collections.Hashtable by adding the -AsHashTable switch. To iterate the hashtable keys and values, we have to use System.Collections.Hashtable.GetEnumerator.

$objects = @'
Number,Color
1,Red
2,Red
3,Red
4,Red
5,Blue
6,Blue
7,Green
8,Green
9,Green
'@ | ConvertFrom-Csv

$ht = $objects | Group-Object -Property Color -AsHashTable

$ht.GetEnumerator() | 
    Select-Object @{Name="Color";Expression={$_.Key}}, @{Name="Number";Expression={$_.Value | Select-Object -ExpandProperty Number}}

Output:

Color Number
----- ------
Green {7, 8, 9}
Red   {1, 2, 3, 4}
Blue  {5, 6}

If we want to sort your result by Number, we can use Sort-Object to sort by the first number:

$ht.GetEnumerator() | 
    Select-Object @{Name="Color";Expression={$_.Key}}, @{Name="Number";Expression={$_.Value | Select-Object -ExpandProperty Number}} |
        Sort-Object @{Expression={$_.Number[0]}}

Or use an System.Collections.Specialized.OrderedDictionary to create an ordered hashtable of arrays and maintain order of key insertion:

$ht = [ordered]@{}
foreach ($object in $objects) {
    if (-not ($ht.Keys -contains $object.Color)) {
        $ht[$object.Color] = @()
    }
    $ht[$object.Color] += $object.Number
}

$ht.GetEnumerator() | 
    Select-Object @{Name="Color";Expression={$_.Key}}, @{Name="Number";Expression={$_.Value}} 

Which will output the following:

Color Number
----- ------
Red   {1, 2, 3, 4}
Blue  {5, 6}
Green {7, 8, 9}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.