Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Perl - Unique Numbers

by deelinux (Novice)
on Oct 17, 2015 at 18:42 UTC ( [id://1145213]=perlquestion: print w/replies, xml ) Need Help??

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

Hello (I'm new to perl and programming) Im trying to create 10 unique numbers from numbers 1 - 20, but every now and then I get duplicates in the listI would like to remove the duplicates or not get one in the first place. This is no doubt due to my coding, so I'm looking for some help. I have run both rand and srand - same results My code

$x=1; $y=20; $looptimes=10; while ($looptimes) { $mynumbers = int(rand ($y - $x + 1)) + $x, "\n"; print $mynumbers; $looptimes--; }
Can anyone help here?

Replies are listed 'Best First'.
Re: Perl - Unique Numbers
by toolic (Bishop) on Oct 17, 2015 at 19:05 UTC
    List::Util
    use warnings; use strict; use List::Util qw(shuffle); for ((shuffle(1..20))[0..9]) { print "$_\n"; }
    1..20 creates an ordered list of numbers from 1 to 20. shuffle randomly orders the list. ()[0..9] is a slice which picks the 1st 10 numbers from the random list.
      Very concise and nice. Use library as much as possible.
Re: Perl - Unique Numbers
by AppleFritter (Vicar) on Oct 17, 2015 at 19:09 UTC

    Howdy, welcome to the Monastery!

    There's many ways that this could be done. For one, you could check the "candidate" in your loop and get another one from rand if you already saw it before. In the following code, I'm using a hash (associative array) to remember which numbers were already seen:

    my $x = 1; my $y = 20; my $looptimes = 10; my %numbers = (); foreach(1 .. $looptimes) { my $candidate = -1; do { $candidate = int(rand ($y - $x + 1)) + $x; } while(exists $numbers{$candidate}); $numbers{$candidate} = 1; } say join ",", keys %numbers;

    If you only care about the result, you could also e.g. take the list of numbers from $x to $y, shuffle it, and then grab the $looptimes numbers. How do I shuffle an array? has more on shuffling arrays; the executive summary is that there's a shuffle function in List::Util (a core module):

    use List::Util qw/shuffle/; my $x = 1; my $y = 20; my $looptimes = 10; my @numbers = shuffle($x .. $y); say join ",", @numbers[0 .. ($looptimes - 1)];

    Though that said I reckon you care more about the "how" than the result.

    Since you're starting out, here's a few general suggestions, too.

    • use strict, and use warnings. They're your friends, and will catch many common mistakes, typos etc. for you.
    • Format your code. Indent loop bodies and other blocks. Add spaces around the equal signs in assignments.
    • Use for or foreach loops (exactly the same, BTW) to do something a given number of times; while loops are more appropriate when you don't know how often something'll have to be done.

    Hope this helps!

Re: Perl - Unique Numbers
by LanX (Saint) on Oct 18, 2015 at 02:43 UTC
Re: Perl - Unique Numbers
by flexvault (Monsignor) on Oct 17, 2015 at 19:27 UTC

    Welcome deelinux

    And another way of doing what you need:

    use strict; use warnings; my $x = 1; my $y = 20; my $looptimes = 10; my %NoDups = (); while( 1 ) { my $num = int( 1 + rand( 19 ) ); if ( exists $NoDups{ $num } ) { next; } $NoDups{ $num } = 1; if ( keys %NoDups >= $looptimes ) { last; } } foreach my $no ( sort {$a<=>$b} keys %NoDups ) { print "$no\n"; }

    Good Luck...Ed

    "Well done is better than well said." - Benjamin Franklin

      I don't think it really matters if the value for a particular number is more than one so the exists test is perhaps overkill. The keys count is what matters.

      $ perl -Mstrict -Mwarnings -E ' my %numbers; $numbers{ int( rand 20 ) + 1 } ++ while keys %numbers < 10; say for sort { $a <=> $b } keys %numbers;' 4 7 8 9 11 13 14 15 17 18 $

      I hope this is of interest.

      Cheers,

      JohnGG

        The OP stated:

          "...but every now and then I get duplicates in the list. I would like to remove the duplicates or not get one in the first place."

        How do you define 'duplicates'?

        Regards...Ed

        "Well done is better than well said." - Benjamin Franklin

Re: Perl - Unique Numbers (algorithm)
by tye (Sage) on Oct 19, 2015 at 14:37 UTC

    Heh, the algorithmically optimal (IMHO) way to get N unique numbers from a set of M of them is not actually covered in any of the replies. Not that this means you shouldn't use any of those solutions. I just think the method should be mentioned.

    The process is the same as that used in List::Util's shuffle(), the Fisher-Yates Shuffle, except you stop early.

    sub tenOf20 { my @set = 1..20; for( 0..9 ) { my $r = $_ + int( rand(@set-$_) ); @set[$_,$r] = @set[$r,$_] if $r != $_; } return @set[0..9]; }

    - tye        

Re: Perl - Unique Numbers
by flexvault (Monsignor) on Oct 19, 2015 at 13:58 UTC

    Dear johngg and dsheroh,

    I do not usually critique the answers of other monks ( unless I think it is wrong :-), since thanks to Perl we have many ways of doing the same thing. When I stated 'OP', I was referring to:

    OP Original Poster The author of the top level node of the thread in which it appears.
    My confusion is that johngg was critiquing my answer to the Original Poster (OP) and I didn't even look at the answer johngg supplied. When I used the word 'trivial', I was referring to the OP's problem and script and not to any monk's comments.

    As for my use of 'exists', I benchmarked on Perl 5.12.2 that 'exists' was faster at checking keys than working on the values of the keys ( $h{$key}++; ). In johngg script, the way he uses the incrementing in his script, it may be faster.

    Let's not have a flame war over my mis-understanding!

    Best Regards...Ed

    "Well done is better than well said." - Benjamin Franklin

Re: Perl - Unique Numbers
by deelinux (Novice) on Oct 18, 2015 at 15:52 UTC

    Hello all, many thanks for all the replies, code and advise, much appreciated!, I now need to digest, and play with your all your recommendations. Dee

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1145213]
Approved by toolic
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having a coffee break in the Monastery: (9)
As of 2024-04-19 08:49 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found