Set::IntSpan can provide relevent routines when working with (connected) ranges of numbers. Although it can work with array references it can be initialized with just a string (and so you save a lot of memory).
#!/usr/bin/perl
use strict;
use warnings;
use Set::IntSpan;
my $range = Set::IntSpan->new( '50000-65535' );
my $used = Set::IntSpan->new( '50000-51545,51549,51555-51999' );
my $unused = $range->diff( $used );
my @newports;
while (my $port = $unused->next) {
print $port, "\n";
push @newports, $port;
last if @newports == 10;
}
print "Unused before newports: ", $unused->run_list, "\n";
for (@newports) {
$unused->remove($_);
$used->insert($_);
}
print "Unused after newports: ", $unused->run_list, "\n";
print "Used after newports: ", $used->run_list, "\n";
__END__
C:\Old_Data\perlp>perl t5.pl
51546
51547
51548
51550
51551
51552
51553
51554
52000
52001
Unused before newports: 51546-51548,51550-51554,52000-65535
Unused after newports: 52002-65535
Used after newports: 50000-52001
Update: Well, as it happens, I shouldn't make statements about that which I don't know (well). The documentation says:
Sets are stored internally in a run-length coded form. This provides for both compact storage and efficient computation. In particular, set operations can be performed directly on the encoded representation...