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

Hi All.

I'm writing a perl script to check if every entry to an array is unique before putting it into an array.

I expected my code would give an output like this:

Enter a number: 1
2
3
3
Already exist
4
^Z
Array is: 1 2 3 4

But I'm getting an infinite loop which doesnt break when I type "^Z"

also it doesnt prompt "already exist" when I enter redudant values

$i=1; @arr=(); print "Enter a number"; while(1) { $val=<>; if ($i eq 1) #Enter the first entry into the +array directly. { push(@arr,$val); # push it into the array 'arr'. } else {for($x=1;$x<=scalar(@arr);$x++) #run through the 'arr'. { if($arr[$x] eq $val) # check if every entry is unique. { print "Already exist at $x position";# if it is not, tell the user t +o enter a unique one and ignore the present (redundant)entry. exit;} else { push(@arr,$val); #If unique, push into the ar +ray. } } } print" @arr \t"; } print "Array is:", @arr; #display the array.

Any help would be appreciated.

Thanks

Replies are listed 'Best First'.
Re: question on Arrays
by jethro (Monsignor) on Jul 29, 2010 at 15:31 UTC

    You never increment $i, so you never will never reach the code where you compare the number to the array

    I could stop the program with ctrl-C without any problems. ctrl-Z would make the program run as a background prozess here on linux, don't know what you have running

    Even if you had changed $i you would not get the right results. You use exit to presumably exit the loop, that is done with last. exit exits the program.

    Also your logic is wrong. When it compares the first value in the array with the new value and it is different, it already pushes the new value into the array. But you have to wait until you compared the new value to ALL values before you can push it. Ergo you need to wait until after the loop before you can add that new value

    Please indent correctly. Your program is very hard to read

    Please 'use warnings;'

    To find out what is happening in a program, put print statements into it and print out variable values. If you had inserted a print statement just before the loop (to find out what is going on) you would have found out that that part of the code was never executed.

Re: question on Arrays
by BioLion (Curate) on Jul 29, 2010 at 15:44 UTC

    Maybe better to use a hash if you are going to check existence?

    use strict; use warnings; ## buffering off ++$|; ## for storing numbers entered so far my %hsh; while (1){ print "Enter something (or nothing if you are bored):\n"; ## get input my $num = <>; chomp $num; ## exit infinite loop if the user hits enter twice last if (!defined$num || $num eq ''); ## check against previous input if (exists $hsh{$num}){ print "Seen >$num< before, try again.\n"; next; } else { print "Oooh >$num< is new, thanks!\n"; ++$hsh{$num}; } } print +(join "\n\t", "Finished! You entered :", sort keys %hsh);

    Sample terminal:

    Enter something (or nothing if you are bored): 4 Oooh >4< is new, thanks! Enter something (or nothing if you are bored): foo Oooh >foo< is new, thanks! Enter something (or nothing if you are bored): bar Oooh >bar< is new, thanks! Enter something (or nothing if you are bored): 4 Seen >4< before, try again. Enter something (or nothing if you are bored): Finished! You entered : 4 bar foo
    Just a something something...
Re: question on Arrays
by derby (Abbot) on Jul 29, 2010 at 15:19 UTC

    To (not) answer your question indirectly -- why do you think entering a CTRL-Z (or CTRL-D) would exit your while loop?

    -derby
      I'm working on Windows., but I'm not sure how else the Array would be displayed if not for typing ^Z, since its an infinite loop. Please correct me ,if I'm worng.

        Your loop is

        while (1) { ... }

        Ctrl-Z does not change the value "1" returns.

        As for your original question,

        my @a; while (my $val = <>) { chomp $val; push @a, $_ if !grep $_ eq $val, @a; }
        or
        my @a; my %seen; while (<>) { chomp; next if $seen{$_}++; push @a, $_; }

        CTRL-Z (end of file) does not break you out of your infinite loop ... so what construct would? Maybe checking if $var has a value? Maybe moving that check into your while so you do not have an infinite loop:

        while( $val = <> )
        There are many ways. Your problem has nothing to do with arrays but with how to write effective control structures. *And* there are more idiomatic ways of figuring out if a value is in an array. Iterating through the array is going to be costly at some point -- you might be better off using a hash to track what's been placed in the array (and ... this really looks like a homework problem).

        -derby
Re: question on Arrays
by dasgar (Priest) on Jul 29, 2010 at 15:43 UTC

    I'm getting a bit confused about what you're trying to do. First, there's nothing in your code that is looking for "^Z" to take an action on. Second, your code has two loops: an infinite while loop and a for loop. I'm guessing that your complaint about an infinite loop is about the for loop.

    With the for loop, I see two problems. First, you are starting your iteration with element ID 1, which is actually the second element of the array. Arrays in Perl are zero based enumerated. Second, scalar(@arr) gives you the total of count of array elements. Instead, you probably should have used $#arr, which would provide you with the last array element ID. In other words, your for loop should have been:

    for($x=1;$x<=$#arr;$x++)

    Anyways, I think that the code below should either do what you're wanting or be close enough to give you a good starting point. It will repeatedly prompt a user for a number and either add it to the array if it doesn't exist in the array or exits out if a duplicate value was given.

    use strict; my @arr; my $exit = 0; while ($exit == 0) { print "Enter a number: "; my $val = <>; chomp $val; if (grep $_ eq $val,@arr) { print "Value already exists.\n"; $exit++; } else { push @arr,($val); } } print "Array contains:\n"; foreach my $elem (@arr) {print "$elem\n";}
Re: question on Arrays
by Utilitarian (Vicar) on Jul 29, 2010 at 15:33 UTC
    When you need to ensure that you have a unique list consider using
    if (! $elements{$x}){ # we haven't seen it before $elements{$x}=1; } else{ print "Seen it\n"; } print join ",", keys(%elements);
    As for your original question, sending an end of file to STDIN has no effect on while(1) you could read each line from STDIN until you hit an end of file.

    print "Good ",qw(night morning afternoon evening)[(localtime)[2]/6]," fellow monks."
Re: question on Arrays
by kennethk (Abbot) on Jul 29, 2010 at 15:41 UTC