http://qs321.pair.com?node_id=11121986

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

Hello Monks, I have wrote a program that stores five numbers in different variables and then calculates the sum of these numbers. Thereafter, it divides each number with the sum and store these in an array. Last, it prints out the entire array to the terminal. I just want to ask is this the good approach which i used? please have a look at my code below

#!/usr/bin/perl -w use warnings; use strict; my $num1 = 5; my $num2 = 10; my $num3 = 15; my $num4 = 20; my $num5 = 25; my $totalSum = $num1 + $num2 + $num3 + $num4 + $num5; my @array = ($num1/$totalSum, $num2/$totalSum, $num3/$totalSum, $num4/ +$totalSum, $num5/$totalSum); print "The required numbers are: @array";

Replies are listed 'Best First'.
Re: Finding sum of numbers and storing it an Array
by tobyink (Canon) on Sep 21, 2020 at 09:11 UTC

    It's an okay way to do it if you understand how it works. For future maintenance, it's better to have code that you understand than code you don't understand.

    But if in the future, you ended up having 20 or 30 numbers instead of five, the code will become pretty nasty. You'll likely get random errors in your results, only to realize after hours of investigation that you included $num17/$totalSum in the array, but forgot to include +$num17 when adding the numbers together. Or something like that.

    For that reason, I'd recommend using an array to keep your numbers in.

    #!/usr/bin/env perl use strict; use warnings; my @nums = ( 5, 10, 15, 20, 25 ); # Loop through the array to add each number, one at a time to make the + total. my $totalSum = 0; for my $num ( @nums ) { $totalSum += $num; } # Map loops through a list, applying a block to each item, to create a + new list my @array = map { $_ / $totalSum } @nums; print "The required numbers are: @array";

    Because adding a list of numbers together is a pretty common thing to do, there's a function called sum that comes with Perl to do it:

    #!/usr/bin/env perl use strict; use warnings; use List::Util 'sum'; my @nums = ( 5, 10, 15, 20, 25 ); my $totalSum = sum @nums; my @array = map { $_ / $totalSum } @nums; print "The required numbers are: @array";

    You probably don't need to worry about whether the user will have List::Util installed. It has been bundled with Perl since 2002.

      the thing is i am not allowed to use maps in this program only array i can use so in this situation is my approach ok? or can it become better using only arrays?

        the thing is i am not allowed to use maps in this program only array

        To be clear, in some programming languages, there's a data structure called a "Map". Java is one such language. It stores a mapping from one set of data (the keys) to another set of data (the values). Perhaps domain names to IP addresses:

        ( "foo.example.com" => "10.0.0.1", "bar.example.com" => "10.0.0.2", "baz.example.com" => "10.0.0.3", )

        Perl doesn't have a native map datatype. For some purposes, Perl hashes can be used. But if the keys can't be reduced to strings, Perl hashes become trickier. (Tied hashes and fieldhashes can work around this limitation to an extent.)

        The Perl map keyword doesn't have anything to do with Map data structures though. It operates on lists. (And an array is basically just a way of storing a list in a variable.)

        Anything you do with map and grep, you can do with plain old loops, but map and grep are often clearer ways to express yourself.

        A way to think of it might be: can you speak/write using only one-syllable words?

        • Yes, you can say all the things you want to say with the use of words that have just one sound part in them.
        • But polysyllabic words sometimes allow for more concise expression.

        You can replace the map with a simple for loop.

        my @array; push @array, $_ / $totalSum for @nums;

        🦛

        > i am not allowed to use maps

        Is it a homework? Or a workplace optimising for newbies? Or maybe some kind of cartography elimination?

        map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
Re: Finding sum of numbers and storing it an Array
by hippo (Bishop) on Sep 21, 2020 at 09:20 UTC
    I have wrote a program that stores five numbers in different variables

    This is the part which is confusing. You clearly know how to use arrays so why not start with an array?

    my @nums = (5, 10, 15, 20, 25);

    That way your sum could be written:

    my $totalSum = 0; $totalSum += $_ for @nums;

    or alternatively

    use List::Util 'sum'; my $totalSum = sum @nums;

    And your final array assignment could become

    my @array = map { $_ / $totalSum } @nums;

    By starting off with separate scalars, everything you do becomes repetitive. It's feasible for 5 numbers, but what about 30? or 100? or 1000000?

    The other thing I would change is to remove the -w from the first line. Using warnings as you have done is better as it gives lexical scope and finer control where needed. The -w negates all that.


    🦛

Re: Finding sum of numbers and storing it an Array
by BillKSmith (Monsignor) on Sep 21, 2020 at 14:02 UTC
    If you are not allowed to use map then it is unlikely that you would be allowed to use modules in this assignment. However, you should be aware that they exist and can be useful even in very small programs. Here I have used List::Util and List::MoreUtils. One big advantage of using these is that the names of the functions suggest what they do.
    use strict; use warnings; use List::Util qw(sum); use List::MoreUtils qw(apply); my @nums = qw( 5 10 15 20 25 ); my $totalSum = sum @nums; my @array = apply {$_ /= $totalSum} @nums; printf "Fractional Parts:\n" . "%8.6f\n" x scalar @array, @array;

    OUTPUT:

    Fractional Parts: 0.066667 0.133333 0.200000 0.266667 0.333333
    Bill
Re: Finding sum of numbers and storing it an Array
by tybalt89 (Monsignor) on Sep 21, 2020 at 11:09 UTC

    With minimal editing...

    #!/usr/bin/perl use strict; # https://perlmonks.org/?node_id=11121986 use warnings; my @numbers = ( my $num1 = 5, my $num2 = 10, my $num3 = 15, my $num4 = 20, my $num5 = 25, ); my $totalSum = 0; $totalSum += $_ for @numbers; $_ /= $totalSum for my @array = @numbers; # just to confuse your t +eacher print "The required numbers are: @array\n";

    Outputs:

    The required numbers are: 0.0666666666666667 0.133333333333333 0.2 0.2 +66666666666667 0.333333333333333