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

Dear all ,
Please help me out
From the following code i want groups of six random no. which total of services must be in between 840 - 900
But problem is that i am getting repeating random No. & that is i don want
as well as all the random no. use....
Help me out thanks in advance
#!/usr/bin/perl -w my @new_lot = qw(1 .. 186); my @A_services =qw(121 182 111 160 105 113 121 97 123 157 133 161 141 +135 137 145 133 137 151 118 126 141 174 181 154 109 198 114 122 162 9 +1 99 116 122 195 199 150 192 163 88 112 157 182 210 124 105 144 166 144 257 164 156 173 + 154 193 142 143 126 118 130 107 86 131 154 131 147 134 118 115 135 141 158 129 + 143 126 128 134 129 167 130 135 117 127 146 96 117 99 99 139 152 149 136 105 1 +24 136 160 160 139 177 115 123 103 150 183 132 171 121 114 111 113 131 144 122 14 +1 111 139 145 109 114 122 103 160 153 147 172 155 122 296 124 112 161 124 311 99 + 157 122 120 198 152 140 162 177 98 138 156 177 103 180 187 173 150 135 168 132 + 196 112 195 126 113 116 105 116 151 216 188 158 121 166 148 132 89 197 92 115 +98 130 103 120 261 143 126 167 203 95 165 129); my @only_unique = (); my $index1 = scalar(@new_lot); my $dd = 0; for(my $o = 0;$o<6;$o++){ my $one1 = int(rand($index1)); if($one1 == 0){$one1 = int(rand($index1));} for(my $four = 0;$four <scalar(@only_unique);$four++){ if($only_unique[$four]== $one1){ $dd++; } } if($dd == 0){ push(@only_unique,$one1); } } my $tt = 0; for (my $p = 0;$p<scalar(@only_unique);$p++){ my $two = $only_unique[$p]; $tt = $tt+$A_services[$two-1]; } my $gurilla = scalar(@only_unique); if($gurilla == 6){ if(($tt <900) && ($tt > 840)){ for(my $iq= 0;$iq< $index1;$iq++){ &is_exist(); } } } sub is_exist(){ my $Tot = 0; my $y = 0;@Ram = (); for(my $h = 0;$h<6;$h++){ my $one = int(rand($index1)); if($one == 0){$one = int(rand($index1));} for(my $dear = 0;$dear <scalar(@only_unique);$dear++){ if($only_unique[$dear] == $one){ $one = int(rand($index1)); if($one == 0){$one = int(rand($index1));} redo; } #$Tot = $Tot + $A_services[$_]; } push(@Ram,$one); } for(my $no = 0 ; $no<scalar(@Ram);$no++){ my $tw = $Ram[$no]; $Tot = $Tot + $A_services[$tw-1]; } if($y == 0){ if(($Tot >840) && ($Tot <900)){ for(my $pune = 0;$pune <scalar(@Ram); $pune++){ push(@only_unique,$Ram[$pune]); } } } } my $total = 0; my $s = int(rand(100)); $file_name = "bha.txt"; open(FH,">$file_name"); my $jogi = 0; for(my $k = 0;$k <scalar(@only_unique);$k++){ my $lol = ""; my $ganesh = $only_unique[$k]; $total = $total+$A_services[$ganesh-1]; if($jogi == 5){$jogi = -1 ; $lol = "__Total: $total "."\n"; $total = 0; } else{$lol = "";} #my $ganesh = $only_unique[$k]; #$total = $total+$A_services[$ganesh-1]; print FH $cat_one[$ganesh-1]."--".$only_unique[$k]."--".$A_service +s[$ganesh-1]." ".$lol; print "$k><$jogi> ".$cat_one[$ganesh-1]."--".$only_unique[$k]."--" +.$A_services[$ganesh-1]." ".$lol; $jogi++; #if($jogi == 5){$jogi= 0;} } close FH; print "\n\n"; my $t5 = 1; foreach (@only_unique){ print $_," "; $t5++; } print "\n";

Replies are listed 'Best First'.
Re: Help Me in following code ::
by toolic (Bishop) on Apr 12, 2010 at 12:41 UTC
    Unrelated to your problem, but will save you lots of typing in the future...

    When you need to initialize an array with a range of numbers, you can use Perl's Range Operators:

    my @new_lot = 1 .. 186;

    It can also be used to create more Perl-ish for loops:

    for(my $o = 0;$o<6;$o++){

    can also be coded as:

    for my $o (0 .. 6){
Re: Help Me in following code ::
by roboticus (Chancellor) on Apr 12, 2010 at 13:25 UTC

    gskoli:

    Just a minor suggestion on your array initialization: It looks like your data may come from a table that you manually split into three vectors. In the future, you may want to try putting the table into your code like so:

    my (@new_lot, @cat_one, @A_services); my @table = qw ( 1 R 182 2 R 111 3 RC 160 4 RC 105 5 R 113 6 RC 121 );

    Then you can split it out into separate tables (if you like) like this:

    while (@table) { push @new_lot, shift @table; push @cat_one, shift @table; push @A_services, shift @table; }

    It adds a little processing time, but makes maintenance quite a bit easier. Alternatively, you can avoid the extra processing and just go ahead and make it an AoA, like this:

    my @table = ( [ qw( 1 R 182 ) ], [ qw( 2 R 111 ) ], [ qw( 3 RC 160 ) ], [ qw( 4 RC 105 ) ], [ qw( 5 R 113 ) ], [ qw( 6 RC 121 ) ], );

    But you'll have to change your coding a little, though, as $cat_one[2] would become $$table[2][1].

    ...roboticus

    UPDATE: Per chromatic's fine suggestion, I changed the lines like $new_lot[@new_lot] = shift @table; to push @new_lot, it makes the code look much nicer.

      while (@table) { $new_lot[@new_lot] = shift @table; $cat_one[@cat_one] = shift @table; $A_services[@A_services] = shift @table; }

      May I suggest push instead?

      while (@table) { push @new_lot, shift @table; push @cat_one, shift @table; push @A_services, shift @table; }
Re: Help Me in following code ::
by BrowserUk (Patriarch) on Apr 12, 2010 at 14:33 UTC
    i want groups of six random no. which total of services must be in between 840 - 900 But problem is that i am getting repeating random No. & that is i don want

    There are several ways to interpret that.

    One way is that you want: groups of six randomly chosen, unique (positive) integers that sum to between 840 - 900 (inclusive?). Here is a sub that will do that:

    #! perl -slw use strict; use List::Util qw[ sum ]; sub nUniqRandsSumTo { my( $n, $target ) = @_; ## Prevent infinite loop. die 'No solution' if ( ( $n * ($n-1) ) / 2 ) > $target; my @rvs; { @rvs = $target; while( @rvs < $n ) { ## pick an element at my $i = int rand @rvs; ## Can't split 0, 1, 2 into two unique values redo if ( my $toSplit = $rvs[ $i ] ) < 3; my $first = int( rand $toSplit ); my $second = $toSplit - $first; ## try again if it split into two equal values redo if $first == $second; ## replace the original with the random pair splice @rvs, $i, 1, $first, $second; } my %seen; ## Do it all from scratch if we got dups ## Can be expensive if the target is close to the limit redo if grep{ ++$seen{ $_ } > 1 } @rvs; } return @rvs; } for( 1 .. 10 ) { my $target = 840 + int( rand 61 ); my @rands = sort{ $a <=> $b } nUniqRandsSumTo( 6, $target ); printf "sum: %3d [ %s ]\n", sum( @rands ), "@rands"; } __END__ c:\test>834245.pl sum: 896 [ 0 27 34 162 197 476 ] sum: 889 [ 35 77 109 179 196 293 ] sum: 878 [ 18 23 77 91 280 389 ] sum: 885 [ 6 37 68 136 154 484 ] sum: 854 [ 7 8 12 70 237 520 ] sum: 899 [ 8 10 29 101 293 458 ] sum: 858 [ 0 28 37 52 367 374 ] sum: 887 [ 1 8 11 22 43 802 ] sum: 899 [ 11 64 65 117 271 371 ] sum: 872 [ 7 14 40 43 154 614 ]

    The way it works is it picks a target between 840 & 900 and then calls the sub with N (6) and the chosen target.

    The sub:

    1. Places the target in an array.
    2. Loops while the size of the array is less than N.
    3. Picks one of the values in the array at random and splits it randomly into 2 values that add up to the original.
    4. Checks for dups and starts again if it has any.

    Other possible interpretations include:

    • The values are not just unique within the groups of six, but also across all the groups.
    • You want all unique groups of 6 (positive) numbers that sum to between your two values.
    • Your target range could be inclusive; exclusive; high or low inclusive only.

    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.
      Thanks ....
      But the range should now not be exclude ...
      In the o/p the group of no. must be in range that is we have defined that means ::: Actually The array look like this
      New Lots   Serv.
      1   121
      2   182
      3   111
      4   160
      5   105
      6   113
      7   121
      8   97

      Here "New Lots" having range of (186) Respected Services are given
      So now i want Such "New Lots" with group of 4/5/6 in such way that it will not be repeated it will not contain zero and respected "Serv." addition must be in between 840-900

        Sorry. But I do not understand this description at all. Maybe someone else will.


        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.
Re: Help Me in following code ::
by cdarke (Prior) on Apr 12, 2010 at 12:23 UTC
    rand only supplies a pseudo random number, you need to seed it using srand.
      srand is needed only in versions of Perl before 5.004. I believe he might want to shuffle a deck of cards (ie there are only four aces, not an infinite supply).
      -1, incorrect. From the rand docs you linked to:
      Automatically calls srand unless srand has already been called.
      There is no need to manually call srand in Perl.
Re: Help Me in following code ::
by GrandFather (Saint) on Apr 13, 2010 at 20:53 UTC

    Please do not make substantial changes to the content of your node without indicating that you have updated it. Doing so often invalidates replies and is prone to making monks less inclined to help.

    True laziness is hard work
      I am sorry ,new user