Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I have a sorted array, containing a list of all the uid's for all users in an LDAP directory. For various reasons, accounts are terminated, and uid's become free. I need to iterate through the array, and find the next unused sequential uid > 1000. Any help is appreciated.

Replies are listed 'Best First'.
Re: Next unused sequential number
by BrowserUk (Patriarch) on Aug 05, 2011 at 17:16 UTC

    Do you mean that if your array contained:

    1001,1002,1003,1004,1006,1007,1009,1010

    You want a function to inspect the array and return 1005?


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      Exactly.

        Unless your array of numbers is huge, I'd use a simple linear search:

        sub first { my $aref = shift; $aref->[ $_ ]+1 != $aref->[ $_+1 ] and return $aref->[ $_ ]+1 for 0 .. $#$aref-1; };; @a = 1000..1100;; splice @a, rand(100), 1 for 1 .. 10;; print @a;; 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 +1014 1015 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 + ... print first( \@a );; 1016

        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.

        Exactly? The array contains 1001, 1002, 1003? Or the array has indexes 1001, 1002, 1003?

        For example:

        use strict; use warnings; use List::MoreUtils qw/firstidx/; @array = qw/ fred tom jenny jeff claire /; $array[3] = undef; my $available_index = firstidx { not defined $_ } @array; $array[$available_index] = 'peter'; print "@array\n"; __END__ fred tom jenny peter claire

        Dave

Re: Next unused sequential number
by Khen1950fx (Canon) on Aug 05, 2011 at 18:13 UTC
    I'd try it like this:
    #!/usr/bin/perl use strict; use warnings; my @arr = qw(1000 1003 1004 1012 1013 1019 1020); my %unused = map {$_ => 1} @arr; my @av = grep {not $unused{$_}} 1000..1020; print "@av\n";
Re: Next unused sequential number
by JavaFan (Canon) on Aug 05, 2011 at 17:30 UTC
    Unless you have an array containing billions of uids, I'd do (untested):
    my @uids = ....; # List of used UIDs my %uids; @uids{@uids} = (); my $uid = 1001; {$uid++, redo if exist $uids{$uid}} say "First unused uid: $uid";
    It doesn't actually need the list to be sorted.

    Alternatively, you can make use of the fact the list is sorted (again, untested):

    my @uids = ....; # List of sorted uids my $uid = 1001; for (my $i = 0; $i < @uids; $i++) { next if $uids[$i] < $uid; last unless $uids[$i] == $uid; $uid++; } say "First unused uid: $uid";
    Note that the latter algorithm isn't Perl specific, and can be trivially ported to many general purpose languages.
      Thank you for your collective wisdome perl monks. I found This to be quite helpful:
      Alternatively, you can make use of the fact the list is sorted (again, + untested): my @uids = ....; # List of sorted uids my $uid = 1001; for (my $i = 0; $i < @uids; $i++) { next if $uids[$i] < $uid; last unless $uids[$i] == $uid; $uid++; } say "First unused uid: $uid";
      My day is going well now!
Re: Next unused sequential number
by Marshall (Canon) on Aug 05, 2011 at 17:43 UTC
    slightly different formulation, but same idea of linear search. sort the array if it might not be in order.
    #!/usr/bin/perl -w use strict; my @x = (1001,1002,1003,1004,1006,1007,1009,1010); print get_next(\@x); #1005 sub get_next { my $aref = shift; my $cur; foreach (sort{$a<=>$b}@$aref) { if (!defined $cur){$cur=$_; next;} return $cur if (++$cur ne $_); } return undef; #search failed - no holes! }