SkullNerd
SkullNerd

Reputation: 57

Powershell - How can I count count occurrences in my array

So I made my input from the read-host into an array an figured it would let me count the amount of times a word in the sentence $a is seen from the $Array. however Count++ doesn't give me a total

   function Get-Sentence($a){
                if($a -contains $array) {
                   $Count++
                }
             else {
                   return 0
                }   
        }
        Write-Host "There are $count words"

        [array]$Array = @("a", "an", "the")
        [array]$a = Read-Host "Enter a long sentence from a story book or novel: ").split(" ")

Upvotes: 0

Views: 3471

Answers (4)

ted
ted

Reputation: 1

$mystring = "abc,123"
$elements = ($element = $mystring -split ",").count
Write-Host($elements)
2
Write-Host($element[0])
abc
Write-Host($element[1))
123

Upvotes: 0

Santiago Squarzon
Santiago Squarzon

Reputation: 60145

Another way to do it using Enumerable.Count, a Hashset<T> for efficiently check if each token is contained in the substrings and -split to trim the white space from the split tokens.

$Substrings = [System.Collections.Generic.HashSet[string]]::new(
    [string[]] ('a', 'an', 'the'),
    [System.StringComparer]::InvariantCultureIgnoreCase)

$Sentence = Read-Host 'Enter a long sentence from a story book or novel: '

[System.Linq.Enumerable]::Count(
    -split $Sentence,
    [Func[string, bool]] { $Substrings.Contains($args[0]) })

Upvotes: 0

Mathias R. Jessen
Mathias R. Jessen

Reputation: 174545

Preferred approach:

Easiest way to accurately count occurrences of multiple substrings is probably:

  1. Construct regex pattern that matches on any one of the substrings
  2. Use the -split operator to split the string
  3. Count the resulting number of strings and substract 1:

# Define the substrings and a sentence to test against
$Substrings = "a","an","the"
$Sentence   = "a long long sentence to test the -split approach, anticipating false positives"

# Construct the regex pattern
# The \b sequence ensures "word boundaries" on either side of a 
# match so that "a" wont match the a in "man" for example
$Pattern = "\b(?:{0})\b" -f ($Substrings -join '|')

# Split the string, count result and subtract 1
$Count = ($Sentence -split $Pattern).Count - 1

Outputs:

C:\> $Count
2

As you can see it will have matched and split on "a" and "the", but not the "an" in "anticipating".

I'll leave converting this into a function an exercise to the reader


Note: if you start feeding more than just simple ASCII strings as input, you may want to escape them before using them in the pattern:

$Pattern = "\b(?:{0})\b" -f (($Substrings |ForEach-Object {[regex]::Escape($_)}) -join '|')

Naive approach:

If you're uncomfortable with regular expressions, you can make the assumption that anything in between two spaces is "a word" (like in your original example), and then loop through the words in the sentence and check if the array contains the word in question (not the other way around):

$Substrings = "a","an","the"
$Sentence   = (Read-Host "Enter a long sentence from a story book or novel: ").Split(" ")

$Counter = 0

foreach($Word in $Sentence){
    if($Substrings -contains $Word){
        $Counter++
    }
}

As suggested by Jeroen Mostert, you could also utilize a HashTable. With this you could track occurrences of each word, instead of just a total count:

$Substrings = "a","an","the"
$Sentence   = (Read-Host "Enter a long sentence from a story book or novel: ").Split(" ")

# Create hashtable from substrings
$Dictionary = @{}
$Substrings |ForEach-Object { $Dictionary[$_] = 0 }

foreach($Word in $Sentence){
    if($Dictionary.ContainsKey($Word)){
        $Dictionary[$Word]++
    }
}

$Dictionary

Upvotes: 2

Esperento57
Esperento57

Reputation: 17472

  $Substrings = "a","an","the"
  ("a long long sentence to test the -split approach, anticipating false positives" -split " " | where {$Substrings -contains $_}).Count

Upvotes: 1

Related Questions