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

Dear Pearl Monks. I am soorry to trouble you with a trifle, but I am struggling with nested loops and if statements. First I shall describe what i am hoping to achieve: A covering set is a set of primes with relationship ymodp in relation to the first member of a range of integers, such that all integers in the range are composite with factors provided by one of more of the primes in the covering set. To get to the most efficient cover, a greedy algorithm might start with small primes and take each in turn on a range of integers, and determining for each prime, the initial relationship ymodp that eliminates the most integers. The next smallest prime is then applied against this reduced set, cycling through the possibilities of ymodx, and the resulting set that has the least members forme the basis for the next prime. Often there will be a tie, with more than one y providing equally small sets, where a simple rule will be to take forward the first one found. Hence for a range of 210 integers, 2 will eliminate 105 members if the relationshpi to the first member is 1mod2 or 0mod2. Take 0mod 2 result as it was found first. 3, the next smallest prime will reduce the set to 70 whether 0mod3, 1mod3, 2mod3. Take 0mod3 as it was fonud first. All 5 mod positions for the prime 5 produce 56 remaining members for 0mod2, 0mod3, and 7 similarly leaves 48. Only at 11 do we get a difference, where the results range from 42 to 45 according to x value in the xmod11. The best of these was 42 from 5 mod11. Taking this best set forward, 12mod13 produces the samllest set, with 36 members. Etc. So I need loops for each prime and for each ymodx, and an if statement if an ymodx produces a better result for that prime, and an output that shows the best reults at each prime and the set taken forward. When I tried to do this, I am OK up to a point, and then I am finding that the program does not choose the lowest ymodx but instead ingores that, and the results after that are gibberish. So I would be grateful for guidance on how to manage these for loops and if statements to produce a result as described above.

#!/usr/bin/env perl use warnings; use strict; use feature ':5.10'; my @primes = (2,3,5,7,11,13,17) ; my @startset = (0..209); my @bestatstartofprime = @startset; my @bestincurrentprime = @startset; foreach my $x (@primes) { @bestatstartofprime = @bestincurrentprime; say "1"," ",$x," ",scalar @bestatstartofprime, " ",scalar @bestinc +urrentprime; my @mods = (0..($x-1)); foreach my $y (@mods) { say "2"," ",$x," ",$y," ",scalar @bestatstartofprime," ",s +calar @bestincurrentprime ; my @cleared = grep { ($_+$y) % $x ne 0} @bestatstartofprim +e; say "3", " ", $x," ",$y," ",scalar @bestatstartofprime," " +,scalar @bestincurrentprime," ",scalar @cleared; if (scalar @cleared lt scalar @bestincurrentprime) { say "4 loop a"," ", $x," ",$y," ",scalar @bestatstarto +fprime, " ", scalar @bestincurrentprime," ",scalar @cleared; @bestincurrentprime = @cleared; say "4 loop b"," ", $x," ",$y," ",scalar @bestatstarto +fprime, " ", scalar @bestincurrentprime," ",scalar @cleared; } say "5", " ", $x," ",$y," ",scalar @bestatstartofprime," " +,scalar @bestincurrentprime; } }

Replies are listed 'Best First'.
Re: Nested loops and if
by poj (Abbot) on Feb 20, 2016 at 20:45 UTC
    results after that are gibberish

    Use a numeric relational operator rather than a stringwise one

    #scalar @cleared lt scalar @bestincurrentprime
    scalar @cleared < scalar @bestincurrentprime

    and less importantly here

    #grep { ($_+$y) % $x ne 0}
    grep { ($_+$y) % $x != 0}
    or just grep { ($_+$y) % $x }

    Update : cut down version

    #!/usr/bin/env perl use warnings; use strict; my @primes = (2,3,5,7,11,13,17) ; my @start = (0..209); foreach my $x (@primes){ my @best = @start; my $count = scalar @best; print "\nprime $x $count\n"; foreach my $y (0..$x-1){ my @new = grep { ($_+$y) % $x } @best; my $new = scalar @new; print " ${y}mod${x} = $new\n"; if ($new < @start){ @start = @new; } } }
    poj

      I'm sorry to trouble again, but I am wondering how I record the $y with the lowest $new for each $x and place this in a file ready for a CRT calculation, given by the "push" command in the program below. For the CRT calculation I only need one $y for each $x, otherwise the CRT calculation will not work. For example, running this code produces 0,11 as well as 5,11 in @results and it is only the last value at for each prime that I need to keep (i.e. 5,11

      #!/usr/bin/env perl use warnings; foreach my $x (@primes){ my @best = @start; my $count = scalar @best; use strict; my @primes = (2,3,5,7,11,13,17) ; my @start = (0..209); my @results =(); print "\nprime $x $count\n"; foreach my $y (0..$x-1){ my @new = grep { ($_+$y) % $x } @best; my $new = scalar @new; print " ${y}mod${x} = $new\n"; if ($new < @start){ @start = @new; push ( @results, ("[","$y",",","$x","],")); } } } foreach (@start) { print "$_\n"; } print "@results\n";

        Move the push down outside the y loop, use another variable like y0 to hold the minimum value

        #!/usr/bin/env perl use strict; use warnings; my @primes = (2,3,5,7,11,13,17) ; my @start = (0..209); my @results =(); foreach my $x (@primes){ my $y0=0; my @best = @start; my $count = scalar @best; print "\nprime $x $count\n"; foreach my $y (0..$x-1){ my @new = grep { ($_+$y) % $x } @best; my $new = scalar @new; print " ${y}mod${x} = $new\n"; if ($new < @start){ @start = @new; $y0 = $y; } } push @results, "[$y0,$x]"; } print "$_\n" for @start; print join(',',@results),"\n";
        poj

      thank you poj, you nailed it!