Reputation: 131
I'm working to find the next available number in a set of numbers and have trouble.
My dataset is an array of strings that is then converted to an array of integers. The original dataset may have duplicate numbers.
When I try and find the next available number, the duplicates seem to cause issues yielding bad results
$dataset = "0001","0002","0004","0006","2","5"
#Convert our strings to integers
[array]$Used = foreach($number in $dataset) {
try {
[int]::parse($number)
} catch {
Invoke-Expression -Command $number;
}
}
[array]::sort($Used)
$range = 1..10
$Available = compare $range $Used -PassThru
My results are:
$Dataset =
0001
0002
0004
0006
2
5
$Used =
1
2
2
4
5
6
Noticed that $Used
(which is sorted) shows that 2
is a duplicate:
$Available =
2
3
7
8
9
10
Finally $Available
lists 2
as an available number which is wrong. 2
is actually used twice and the correct answer should be 3
.
Any ideas?
Upvotes: 2
Views: 1122
Reputation: 438208
Converting your strings to numbers can be done with a simple cast:
$dataset = "0001","0002","0004","0006","2","5"
$numbers = [int[]] $dataset
To sort these numbers and eliminate duplicates:
$uniqueSortedNumbers = $numbers | Sort-Object -Unique
To find the first available number inside the resulting list, or possibly the next higher number:
# Find the first gap in the list of sorted numbers, if any.
$nextAvailableNumber =
Compare-Object -PassThru $uniqueSortedNumbers (1..($uniqueSortedNumbers[-1])) |
Select-Object -First 1
# If there was no gap, use the highest number + 1
if ($null -eq $nextAvailableNumber) {
$nextAvailableNumber = $uniqueSortedNumbers[-1] + 1
}
As for what you tried:
Compare-Object
lists objects that are unique to either collection.
By having duplicates in $used
, the duplicates are also reported as unique, because $range
has no duplicate counterparts.
With -PassThru
, the unique values are passed through without (obvious) distinction as to which input collection they're unique to, so you end up with a mix of numbers unique to either collection, comprising both the numbers unique to $range
and the duplicates, which explains your symptom.
By eliminating duplicates from $used
beforehand, the problem is avoided, because all unique values are then guaranteed to be from $range
only.
Upvotes: 1
Reputation: 7479
the Compare-Object
cmdlet always confuses me [blush], so i avoided it entirely. [grin] this works by ...
[string]
items into [int]
items here's the code ...
$DataSet = '0001','0002','0004','0006','2','5'
$UsedNumbers = $DataSet.
ForEach({[int]$_}) |
Sort-Object -Unique
$TargetRange = 1..10
$AvailableNumbers = $TargetRange.
Where({
$_ -notin $UsedNumbers
})
$AvailableNumbers
output ...
3
7
8
9
10
Upvotes: 0
Reputation: 452
This question has been answered before: Removing duplicate values from a PowerShell array
Lots of great answer options, but basically:
$Used = $Used | select -uniq
or another option
$Used | sort -uniq
Upvotes: 1