19

If I have an array:

1 1 1 2 2 3 4 4 4 4 5 5

How can I use Powershell to tell me how many of each element there are in that array?

To be a little more clear, I should have a separate count for each array element:

Element:Count

1:3

2:2

3:1

4:4

5:2

3 Answers 3

38

You can use the Group-Object cmdlet:

PS> 1,1,1,2,2,3,4,4,4,4,5,5 | group

Count Name                      Group
----- ----                      -----
    3 1                         {1, 1, 1}
    2 2                         {2, 2}
    1 3                         {3}
    4 4                         {4, 4, 4, 4}
    2 5                         {5, 5}

If you want a hashtable for the items and their counts you just need a little ForEach-Object after it:

$array | group | % { $h = @{} } { $h[$_.Name] = $_.Count } { $h }
Sign up to request clarification or add additional context in comments.

6 Comments

Thanks for this. What would be an elegant way to derive the mode (most frequently occurring value) of the original array? That is, given the OP's array 1 1 1 2 2 3 4 4 4 4 5 5, I need to return 4.
@IfediOkonkwo: 1,1,1,2,2,3,4,4,4,4,5,5 | group -NoElement | sort Count | select -last 1 -expandProperty Name. A bit long, but each part of that pipeline does a single thing and composes well. Another option would be to separate getting the value and picking the last one with ... | group -NoElement | sort Count | % Name | select -last 1.
@Joey: thanks a million. Before noticing your response, I'd cobbled something together, that worked, though more unwieldy than yours: $hash = $Array | group | % { $h = @{} } { $h[$_.Name] = $_.Count } { $h }; $mode = $hash.GetEnumerator() | Sort-Object -Property Value -Descending | Select-Object -First 1
@mklement0: I completely agree with you. But then, it's only human that laziness sometimes gets the better of you. Hopefully, google can still lead searchers to this very thread ;)
@IfediOkonkwo: Alternatively, we can do the right thing. Note that your solution doesn't handle the case where multiple values occur most frequently.
|
7

You can adjust the output and format it as you like:

PS> $ht= 1,1,1,2,2,3,4,4,4,4,5,5 | Group-Object -AsHashTable -AsString
PS> $ht

Name                           Value
----                           -----
2                              {2, 2}
4                              {4, 4, 4, 4}
5                              {5, 5}
1                              {1, 1, 1}
3                              {3}


PS> $ht['1']
1
1
1

2 Comments

They wanted the counts, though. Thus -AsHashTable is of little help.
$ht['#'].count, in System.Collections.Hashtable it contains a method called count
7

Joey's helpful answer provides the crucial pointer: use the Group-Object cmdlet to group input objects by equality.
(To group them by one ore more of their property values instead, use -Property).

Group-Object outputs [Microsoft.PowerShell.Commands.GroupInfo] objects that each represent a group of equal input objects, whose notable properties are:

  • .Values ... the value(s) that define the group, as a [System.Collections.ArrayList] instance (which has just 1 element in the case at hand, since the input objects as a whole are used to form the groups).

  • .Count ... the count of objects in that group.

If, as in this case, there is no need to collect the individual group members as part of each group,
-NoElement can be used for efficiency.

You're free to further process the group objects as needed; to get the specific output format stipulated in your question, you can use Select-Object with a calculated property.

To put it all together:

PS> 1, 1, 1, 2, 2, 3, 4, 4, 4, 4, 5, 5 | Group-Object -NoElement |
      Select-Object @{ n='Element:Count'; e={ '{0}:{1}' -f $_.Values[0], $_.Count } }

Element:Count
-------------
1:3
2:2
3:1
4:4
5:2

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.