Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

Decimal Array range

by packetstormer (Monk)
on Dec 21, 2010 at 10:33 UTC ( [id://878210]=perlquestion: print w/replies, xml ) Need Help??

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

Hello, As a newbie I can see that you enter and range in an array as follows:
 @array = (1..100);
This should create an array from 1 to 100 inclusive. Is there anyway to create the same type of array with decimal values? e.g
@array = (5.01..12.00) I am really trying to do this with time ranges, say from 1pm to 11pm but not sure that is possible either.

Replies are listed 'Best First'.
Re: Decimal Array range
by BrowserUk (Patriarch) on Dec 21, 2010 at 10:49 UTC

    @decimals = map{$_/100 } 501 .. 512;; print "@decimals";; 5.01 5.02 5.03 5.04 5.05 5.06 5.07 5.08 5.09 5.1 5.11 5.12 @times = map{ sprintf "%02d:%02d", $_/60, $_%60 } 4*60+55 .. 5*60+05;; print "@times";; 04:55 04:56 04:57 04:58 04:59 05:00 05:01 05:02 05:03 05:04 05:05

    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: Decimal Array range
by bart (Canon) on Dec 21, 2010 at 13:02 UTC
    Perl's .. operator can do magic increments, but only for strings in the format /^[a-z]*[0-9]*$/i. But the problem you face here is that your increments must be by 1; not 1/100, not 5 minutes or 1 hour or whatever.

    You'll have to somehow produce a range where increments are one, and scale them.

    Plenty of people showed you how to do that with increments of 1/100, and here's a way to increment using time (in this exampel: increment in 5 minute intervals):

    use POSIX qw(strftime); use Time::Local; my($from, $to, $incr) = ('13:00', '23:00', '0:05'); foreach($from, $to, $incr) { if(/^(\d+):(\d\d)(?::(\d\d))?$/) { $_ = ($1 * 60 + $2) * 60 + ($3 || 0); } } @range = map { strftime "%H:%M:%S", gmtime $_ } map $_*$incr, $from/$incr .. $to/$incr; $_ = join " ", @range; s/(.{1,70})(\s|$)/$1\n/g; print ;
    Output:
    13:00:00 13:05:00 13:10:00 13:15:00 13:20:00 13:25:00 13:30:00 13:35:00 13:40:00 13:45:00 13:50:00 13:55:00 14:00:00 14:05:00 14:10:00 14:15:00 14:20:00 14:25:00 14:30:00 14:35:00 14:40:00 14:45:00 14:50:00 14:55:00 15:00:00 15:05:00 15:10:00 15:15:00 15:20:00 15:25:00 15:30:00 15:35:00 15:40:00 15:45:00 15:50:00 15:55:00 16:00:00 16:05:00 16:10:00 16:15:00 16:20:00 16:25:00 16:30:00 16:35:00 16:40:00 16:45:00 16:50:00 16:55:00 17:00:00 17:05:00 17:10:00 17:15:00 17:20:00 17:25:00 17:30:00 17:35:00 17:40:00 17:45:00 17:50:00 17:55:00 18:00:00 18:05:00 18:10:00 18:15:00 18:20:00 18:25:00 18:30:00 18:35:00 18:40:00 18:45:00 18:50:00 18:55:00 19:00:00 19:05:00 19:10:00 19:15:00 19:20:00 19:25:00 19:30:00 19:35:00 19:40:00 19:45:00 19:50:00 19:55:00 20:00:00 20:05:00 20:10:00 20:15:00 20:20:00 20:25:00 20:30:00 20:35:00 20:40:00 20:45:00 20:50:00 20:55:00 21:00:00 21:05:00 21:10:00 21:15:00 21:20:00 21:25:00 21:30:00 21:35:00 21:40:00 21:45:00 21:50:00 21:55:00 22:00:00 22:05:00 22:10:00 22:15:00 22:20:00 22:25:00 22:30:00 22:35:00 22:40:00 22:45:00 22:50:00 22:55:00 23:00:00

    Tweaking the format spec for strftime you can produce a different time format.

      I didn't realize you could assign to $_ inside a foreach loop and it will change the scalars in the list.

        In foreach, the loop variable (default $_) is an alias to the original value. That means that changing the value will change the original.
        my $x = 100; my @y = (10, 20, 30); foreach ($x, @y) { $_ *= 2; } local $" = ", "; print "\$x = $x\n\@y = (@y)\n";
        # or: foreach my $n ($x, @y) { $n *= 2; }

        Ditto in the block or expression for map and grep ($_ only).

        map { $_ *= 2 } $x, @y;
        grep { $_ *= 2 } $x, @y;

        BTW parameters to subs are aliases too, so if you change them in @_, you'll modify the originals too:

        sub double { foreach(@_) { $_ *= 2; } } double($x, @y);
Re: Decimal Array range
by Anonymous Monk on Dec 21, 2010 at 10:42 UTC
Re: Decimal Array range
by thargas (Deacon) on Dec 21, 2010 at 12:58 UTC

    Think about what you're asking for. What does a time range from 1pm to 11pm mean? One item per hour? One item per minute? Per second? Every 30 seconds? ... The range operator ".." isn't smart enough to read your mind and isn't complicated enough to provide a way for you to tell it.

    You'll have to build up your list by hand

Re: Decimal Array range
by sundialsvc4 (Abbot) on Dec 21, 2010 at 16:09 UTC

    When you have a reasonably-sized range of real-numbered values, it is actually cleanest to simply define a list (or an array) of the actual values you want to use.

    If the values represent known multiples of some base value, you can use an integer range and, within that range, do the necessary calculation.   Or, you might use a while loop, initializing the variable outside the loop and adding to its value at the end of the loop.

    There are many ways to do it.   Pick one that is both abundantly-clear and easily maintainable.   Remember, “requirements change,” and you will not be (nor will you want to be...) in your present job forever.

Re: Decimal Array range
by ikegami (Patriarch) on Dec 21, 2010 at 18:14 UTC

    You're thinking of something like BASIC's STEP clause, in effect. You can achieve this using a C-style loop:

    for (my $i = 0; $i < 100; $i += 0.1) { say $i; }

    but then you can end up with an accumulation of floating point error.*

    ... 99.7999999999986 99.8999999999986 99.9999999999986

    The solution is to use an integer for the loop counter, and calculate the decimal number from it.

    for (my $_ = 0*10; $_ < 100*10; ++$_) { my $i = $_/10; say $i; }
    ... 99.7 99.8 99.9

    Now that you're using integers, you can use a cleaner syntax.

    for (0*10..100*10) { my $i = $_/10; say $i; }

    You already been shown how this get the numbers as a list.

    map $_/10, 0*10..100*10

    * — A lot of numbers are periodic in binary. For example, 1/10 is perodic is binary, just like 1/3 is periodic in decimal. It would take infinite storage to store 1/10 as a floating point number.

Re: Decimal Array range
by Anonymous Monk on Dec 21, 2010 at 18:10 UTC

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others about the Monastery: (4)
As of 2024-03-19 10:47 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found