This is not an answer, it is a performance test, and results, of the answers
This is the test code and results for the code examples provided by Mathias, iRon, and Santiago.
If anyone spots any errors, logic or otherwise, please let me know so I can correct it.
Setup for the test:
Defines the array and variables used in the test.
function Get-RandomAlphaNumericString{
[OutputType([string])]
param (
[parameter(Mandatory = $false, Position = 0)]
[ValidateScript({$_ -gt 0})]
[int]$Length = 1
)
[char[]]$Chars = [char[]]::new($Length)
for ($i = 0; $i -lt $Length; $i++) {
$Chars[$i] = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'[(Get-Random -Maximum 62)]
}
return [string]::new($Chars)
}
function Get-RandomAlphaNumericStrings{
[OutputType([string[]])]
param (
[parameter(Mandatory = $false, Position = 0)]
[ValidateScript({$_ -gt 0})]
[int]$ArrayLength = 1,
[parameter(Mandatory = $false, Position = 1)]
[ValidateScript({$_ -gt 0})]
[int]$StringLength = 1
)
[string[]]$Strings = [string[]]::new($ArrayLength)
for ($i = 0; $i -lt $ArrayLength; $i++) {
$Strings[$i] = Get-RandomAlphaNumericString $StringLength
}
return $Strings
}
$ArraySize = 100000
$LoopCount = 100
$SearchStringLength = 5
$arr = Get-RandomAlphaNumericStrings $ArraySize 20
[int]$IdxAt10Percent = $arr.Length * 0.1
[int]$IdxAt50Percent = $arr.Length * 0.5
[int]$IdxAt90Percent = $arr.Length * 0.9
$At10PercentPrefix = $arr[$IdxAt10Percent].Substring(0, $SearchStringLength)
$At50PercentPrefix = $arr[$IdxAt50Percent].Substring(0, $SearchStringLength)
$At90PercentPrefix = $arr[$IdxAt90Percent].Substring(0, $SearchStringLength)
$IsMissingPrefix = '####################'.Substring(0, $SearchStringLength)
$At10PercentLike = $At10PercentPrefix + '*'
$At50PercentLike = $At50PercentPrefix + '*'
$At90PercentLike = $At90PercentPrefix + '*'
$ThatIsMissingLike = $IsMissingPrefix + '*'
Mathias test code:
Write-Host "`nMathias:"
Write-Host " Array of $ArraySize elements"
Write-Host " Repeat for $LoopCount loops"
$NotFound = $false
Measure-Command {&{
for ($i = 0; $i -lt $LoopCount; $i++) {
if(-not(@($arr) -like $At10PercentLike)){
$NotFound = $true
}
}
}} | ForEach-Object { Write-Host "Index Position = ${IdxAt10Percent}: { $($_.Seconds + $_.Milliseconds/1000) seconds }"}
$NotFound = $false
Measure-Command {&{
for ($i = 0; $i -lt $LoopCount; $i++) {
if(-not(@($arr) -like $At50PercentLike)){
$NotFound = $true
}
}
}} | ForEach-Object { Write-Host "Index Position = ${IdxAt50Percent}: { $($_.Seconds + $_.Milliseconds/1000) seconds }"}
$NotFound = $false
Measure-Command {&{
for ($i = 0; $i -lt $LoopCount; $i++) {
if(-not(@($arr) -like $At90PercentLike)){
$NotFound = $true
}
}
}} | ForEach-Object { Write-Host "Index Position = ${IdxAt90Percent}: { $($_.Seconds + $_.Milliseconds/1000) seconds }"}
$NotFound = $false
Measure-Command {&{
for ($i = 0; $i -lt $LoopCount; $i++) {
if(-not(@($arr) -like $ThatIsMissingLike)){
$NotFound = $true
}
}
}} | ForEach-Object { Write-Host "Missing: { $($_.Seconds + $_.Milliseconds/1000) seconds }"}
iRon's test code:
Write-Host "`niRon:"
Write-Host " Array of $ArraySize elements"
Write-Host " Repeat for $LoopCount loops"
$NotFound = $false
Measure-Command {&{
for ($i = 0; $i -lt $LoopCount; $i++) {
if (!($Arr.StartsWith($At10PercentPrefix) -eq $True)) {
$NotFound = $true
}
}
}} | ForEach-Object { Write-Host "Index Position = ${IdxAt10Percent}: { $($_.Seconds + $_.Milliseconds/1000) seconds }"}
$NotFound = $false
Measure-Command {&{
for ($i = 0; $i -lt $LoopCount; $i++) {
if (!($Arr.StartsWith($At50PercentPrefix) -eq $True)) {
$NotFound = $true
}
}
}} | ForEach-Object { Write-Host "Index Position = ${IdxAt50Percent}: { $($_.Seconds + $_.Milliseconds/1000) seconds }"}
$NotFound = $false
Measure-Command {&{
for ($i = 0; $i -lt $LoopCount; $i++) {
if (!($Arr.StartsWith($At90PercentPrefix) -eq $True)) {
$NotFound = $true
}
}
}} | ForEach-Object { Write-Host "Index Position = ${IdxAt90Percent}: { $($_.Seconds + $_.Milliseconds/1000) seconds }"}
$NotFound = $false
Measure-Command {&{
for ($i = 0; $i -lt $LoopCount; $i++) {
if (!($Arr.StartsWith($IsMissingPrefix) -eq $True)) {
$NotFound = $true
}
}
}} | ForEach-Object { Write-Host "Missing: { $($_.Seconds + $_.Milliseconds/1000) seconds }"}
Santiago's test code:
Write-Host "`nSantiago:"
Write-Host " Array of $ArraySize elements"
Write-Host " Repeat for $LoopCount loops"
$NotFound = $false
Measure-Command {&{
for ($i = 0; $i -lt $LoopCount; $i++) {
$comparison = foreach ($str in $arr) {
if ($str.StartsWith($At10PercentPrefix)) {
$true
break
}
}
if(-not $comparison) {
$NotFound = $true
}
}
}} | ForEach-Object { Write-Host "Index Position = ${IdxAt10Percent}: { $($_.Seconds + $_.Milliseconds/1000) seconds }"}
$NotFound = $false
Measure-Command {&{
for ($i = 0; $i -lt $LoopCount; $i++) {
$comparison = foreach ($str in $arr) {
if ($str.StartsWith($At50PercentPrefix)) {
$true
break
}
}
if(-not $comparison) {
$NotFound = $true
}
}
}} | ForEach-Object { Write-Host "Index Position = ${IdxAt50Percent}: { $($_.Seconds + $_.Milliseconds/1000) seconds }"}
$NotFound = $false
Measure-Command {&{
for ($i = 0; $i -lt $LoopCount; $i++) {
$comparison = foreach ($str in $arr) {
if ($str.StartsWith($At90PercentPrefix)) {
$true
break
}
}
if(-not $comparison) {
$NotFound = $true
}
}
}} | ForEach-Object { Write-Host "Index Position = ${IdxAt90Percent}: { $($_.Seconds + $_.Milliseconds/1000) seconds }"}
$NotFound = $false
Measure-Command {&{
for ($i = 0; $i -lt $LoopCount; $i++) {
$comparison = foreach ($str in $arr) {
if ($str.StartsWith($IsMissingPrefix)) {
$true
break
}
}
if(-not $comparison) {
$NotFound = $true
}
}
}} | ForEach-Object { Write-Host "Missing: { $($_.Seconds + $_.Milliseconds/1000) seconds }"}
Typical PowerShell 5.1 results:
Mathias:
Array of 100000 elements
Repeat for 100 loops
Index Position = 10000: { 3.937 seconds }
Index Position = 50000: { 3.917 seconds }
Index Position = 90000: { 3.919 seconds }
Missing: { 3.919 seconds }
iRon:
Array of 100000 elements
Repeat for 100 loops
Index Position = 10000: { 17.514 seconds }
Index Position = 50000: { 17.589 seconds }
Index Position = 90000: { 17.45 seconds }
Missing: { 17.502 seconds }
Santiago:
Array of 100000 elements
Repeat for 100 loops
Index Position = 10000: { 0.749 seconds }
Index Position = 50000: { 3.706 seconds }
Index Position = 90000: { 6.684 seconds }
Missing: { 7.287 seconds }
Typical PowerShell Core 7.2.6 results:
Mathias:
Array of 100000 elements
Repeat for 100 loops
Index Position = 10000: { 1.063 seconds }
Index Position = 50000: { 1.063 seconds }
Index Position = 90000: { 1.057 seconds }
Missing: { 1.051 seconds }
iRon:
Array of 100000 elements
Repeat for 100 loops
Index Position = 10000: { 10.514 seconds }
Index Position = 50000: { 10.818 seconds }
Index Position = 90000: { 10.713 seconds }
Missing: { 10.57 seconds }
Santiago:
Array of 100000 elements
Repeat for 100 loops
Index Position = 10000: { 0.367 seconds }
Index Position = 50000: { 1.697 seconds }
Index Position = 90000: { 3.085 seconds }
Missing: { 3.329 seconds }
Code Corrections:
Santiago pointed out:
When doing performance tests with Measure-Command, I would recommend
you to always wrap all the code inside another scriptblock and execute
it with & to have fair and more accurate results
To my surprise, this makes a notable difference. It isolates the code being tested from the code doing the test. Read Santiago's comment for his description of the problem.