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

Update

I've made progress thanks to the input here. I'm having a little trouble with the error handling. Basically what I want is for the error checking to see if the input is gt or lt the array index or = to 0. It works great unless a value input is gt an index. When greater, I get:

Use of uninitialized value within @vdbhosts in regexp compilation at ./deploy-beta line 129, <> line 2.

This corresponds to this line of code

if (($i =~ $vdbhosts[$i - 1])||($i == 0)){

Here is the full code

# Get count of hosts found for the specified cluster my $chostcounter = 0; foreach my $chost (@$host_views) { $chostcounter++; } # Check that hosts exist, display error and re-direct to CLUSTER: if ($chostcounter == 0){ print "\n"; print BOLD WHITE ON_RED, "Error: No hosts were found in the " . $c +luster_name . " cluster!\n", RESET; goto CLUSTER; } # Export cluster hosts list to a file my $chosts_file = '/root/deploypoc/export/cluster_hosts.txt'; open (CHOSTSFILE, '>', $chosts_file) or die " Problem opening $chosts_ +file\n"; foreach my $chost (@$host_views) { print CHOSTSFILE $chost->{'name'}, "\n"; } close CHOSTSFILE; # VDB host selection print BOLD WHITE ON_BLUE, " Host Selection: The following hosts were found for the + \n" . " specified cluster. Please select the number(s)that + \n" . " correspond to the desired host(s). If entering more than + \n" . " one (1), separate each entry with a comma (1,2,3...) + \n", RESET; print "\n"; # Import cluster hosts list and print sorted output use File::Slurp; my @chosts = read_file($chosts_file); my @vdbhosts = sort @chosts; CLUSTER_HOSTS: foreach my $i (0..$#vdbhosts ) { printf '%-2s',""; print $i + 1 . ". $vdbhosts[$i]"; } print "\n"; ASSIGN_VDB_HOSTS: # Select the hosts from the list above print "Enter selection(s): "; my $vdbhostinput = (<>); chomp $vdbhostinput; print "\n"; my @vdblist = split(',', $vdbhostinput); print "The following hosts were selected:\n\n"; foreach my $i (@vdblist){ # Check to ensure user input is valid and display selected hosts if (($i != $vdbhosts[$i - 1])||($i == 0)){ print BOLD WHITE ON_RED; print "Error: $i does not correspond to a host in the list!"; print RESET; print "\n\n"; goto CLUSTER_HOSTS; } print " " . $i . ". " . $vdbhosts[$i - 1]; }

Replies are listed 'Best First'.
Re: Adding a numeric key to list items and creating a user selection list
by hippo (Archbishop) on Sep 25, 2015 at 09:35 UTC
    What I get now is the index that starts at 0 and that's not what I want.

    Obvious solution: add 1 to each number.

    my @vdbhosts = sort @lines; foreach my $i (0..$#vdbhosts) { print " " . $i + 1 . ". $vdbhosts[$i]\n"; } print "\n";

    Then when you've retrieved the number from the user simply subtract 1 to obtain the index in the array. eg:

    my ($userinput) = (<> =~ /([0-9]+)/g); die "User did not input a number" unless defined $userinput; die "User's number ($userinput) is out of range" unless (0 < $userinpu +t and $#vdbhosts >= $userinput - 1); print "Your choice was number $userinput which is " . $vdbhosts[$useri +nput - 1] . "\n";

    Or is there some deeper problem which I've missed?

    Expert's note: You can change the starting index of an array to be 1 instead of 0. But don't do that unless/until you know what you're doing.

      I implemented the first portion of code and it did exactly what I wanted. I now have a list with all returned items ordered from 1 to X. I issue though. The first portion of the print line is supposed to indent the list by 2 spaces. The spaces are being ignored and instead the list is left justified to the edge of the screen.

      Second portion works as well, however I need to modify it a bit to get what I want. My goal is to allow for input of multiple numbers separated by commas which would then be printed to a text file with each entry being on a new line. Working on this part now.

      Thank you!

        The first portion of the print line is supposed to indent the list by 2 spaces. The spaces are being ignored and instead the list is left justified to the edge of the screen.

        There are plenty of options for formatted output in Perl. However, the most straight forward (particularly with those familiar with it from other languages) is likely to be printf.

Re: Adding a numeric key to list items and creating a user selection list
by 1nickt (Canon) on Sep 25, 2015 at 05:43 UTC

    Use a counter:

    my @vdbhosts = sort @lines; my $count = 1; for ( @vdbhosts ) { print "$count: $vdbhosts[ $count ]\n"; $count++; }
    Also, don't use File::Slurp -- it's broken. Use File::Slurper or Path::Tiny instead.

    Hope this helps!

    The way forward always starts with a minimal test.

      This sort of worked. When I use this code as specified, I get results numbered 1 - 7. The problem is there are 8 records in the file. It skips the first item in the array with the index of 0. If I change it to count = 0, I get all 8 items but numbered starting at 0

        Cool! Besides the solution you were shown involving adding one to the index before you print it, you could also use unshift to pad the array and work with its true index:

        my @vdbhosts = sort @lines; unshift @vdbhosts, 'padding'; my $count = 0; for ( @vdbhosts ) { my $host = $vdbhosts[ $count ]; print "$count: $host\n" unless $host eq 'padding'; $count++; }
        Hope this helps!

        Edit: added alternative solution example, my original reply didn't add much ;-)

        The way forward always starts with a minimal test.

        Add an unused entry to the front of the array, then indexes will align with the data in the way you want.

        Here's a partial example:

        #!/usr/bin/perl # http://perlmonks.org/?node_id=1143022 use strict; use warnings; my @names = qw( aaa bbbb ccccc dddd ee fffff gggg hhhhhh ); # add unused item to front to align names with indexes unshift @names, 'unused'; for my $index (1 .. $#names) { printf "%2d %s\n", $index, $names[$index]; } print "\nselect desired by number:\n"; my $in = <STDIN>; # validate input chomp $in; $in =~ /^[\d,\s]+$/ or die "$in is an invalid input"; for my $index ($in =~ /\d+/g ) { if( $index >= 1 and $index <= $#names ) { print "selected $names[$index]\n"; } else { die "$index is outside the allowable range\n"; } }

        This is perl. Why try to cope with "off by one" (add 1 or subtract 1?) if you don't have to? :)

Re: Adding a numeric key to list items and creating a user selection list (little example)
by Discipulus (Canon) on Sep 25, 2015 at 08:06 UTC
    Hello stevek1974 and welcome to the monastery and the wonderful world of Perl,

    I present a little, and ugly, program that do what you described. You mention that you want the resulting index starting at 1. You know is easier following the array rule, i.e. start with 0. More: i presented a solution using array as you asked even if i prefere using hashes because their keys are unique and the code below admit duplicate entries (input: 1,1,1,1 lead to unwanted results IMHO)
    #!/usr/bin/perl use strict; use warnings;<P> my @names = qw (Tizio Caio Sempronio);<P> show_indexed();<P> my @selected = select_by_index(); print "First choice:\n--->",(join "\n--->",@selected),"\n";<P> ## and then.. push @names,'stevek1974'; show_indexed();<P> my @selected_bis = select_by_index(); print "Second choice:\n--->",(join "\n--->",@selected_bis),"\n";<P> ###################################################################### +########## sub show_indexed { print "\nChoice one or more name, using their index:\n"; my $index = 0; foreach my $name (@names){ print "[$index]\t$name\n"; $index++; } print "\n"; } ###################################################################### +########## sub select_by_index { my $in = <STDIN>; chomp $in; # checks are needed in thi case.. unless ($in=~/^[\d,]+$/){warn "WARNING: invalid input!\n";select_b +y_index()}<P> my @choice = @names[split /,/, $in];#thanks to tye and choroba: i +used @names[eval $in] # more checks are better.. unless (defined $choice[0]){ warn "WARNING: probably you need to check that input numbe +rs are valid for the current array!\n"; select_by_index() } return @choice; }
    Update: the above script is too simple and bugged too: after an invalid input is no more possible to give a valid one!

    HtH
    L*
    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.

      I am actually working with the snippet provided by hippo. It is working for the most part and I've modified it a bit to get to my end goal. I just need to fix formatting a bit and add the error checking, but so far so good.

      Thanks for your suggestion as well.

Re: Adding a numeric key to list items and creating a user selection list
by Anonymous Monk on Sep 25, 2015 at 01:26 UTC

    What I need help with is assigning a number from 1 to X to each item in the array. Then, making sure that the value associated with that number is the items value and not the number.

    Which part of the code is supposed to do that?