Mike C
Mike C

Reputation: 131

Find next number in a sequence

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

Answers (3)

mklement0
mklement0

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

Lee_Dailey
Lee_Dailey

Reputation: 7479

the Compare-Object cmdlet always confuses me [blush], so i avoided it entirely. [grin] this works by ...

  • converting the data set [string] items into [int] items
  • removing the dupes
  • filtering for target range numbers that are NOT in the used numbers list

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

BentChainRing
BentChainRing

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

Related Questions