Renages

All,

I have a requirement to translate a time between 0000 and 2359 in to a
single character 'interval ID' based on the time. For example, if the
time is between 0000 and 0059, '0' should be returned, if it's between
0100 and 0159, '1' should be return. The problem is that 0700-0729
should return 'A', 0730-0759 should return 'B', i.e. it's not a simple
mapping.

I have the following, but I can't help thinking there's a much more
efficient way of doing it - can anyone advise, as I'm a little stuck!

  xlate = [ [ '0000', '0059', '0' ], [ '0100', '0159', '1' ],
            [ '0200', '0259', '2' ], [ '0300', '0359', '3' ],
            [ '0400', '0459', '4' ], [ '0500', '0559', '5' ],
            [ '0600', '0659', '6' ], [ '0700', '0729', 'A' ],
            [ '0730', '0759', 'B' ], [ '0800', '0829', 'C' ],
            [ '0830', '0859', 'D' ], [ '0900', '0929', 'E' ],
            [ '0930', '0959', 'F' ], [ '1000', '1029', 'G' ],
            [ '1030', '1059', 'H' ], [ '1100', '1129', 'I' ],
            [ '1130', '1159', 'J' ], [ '1200', '1229', 'K' ],
            [ '1230', '1259', 'L' ], [ '1300', '1329', 'M' ],
            [ '1330', '1359', 'N' ], [ '1400', '1429', 'O' ],
            [ '1430', '1459', 'P' ], [ '1500', '1529', 'Q' ],
            [ '1530', '1559', 'R' ], [ '1600', '1629', 'S' ],
            [ '1630', '1659', 'T' ], [ '1700', '1729', 'U' ],
            [ '1730', '1759', 'V' ], [ '1800', '1829', 'W' ],
            [ '1830', '1859', 'X' ], [ '1900', '1959', 'Y' ],
            [ '2000', '2059', 'Z' ], [ '2100', '2159', '7' ],
            [ '2200', '2259', '8' ], [ '2300', '2359', '9' ] ]

  xlate.each do |range|
    return range[2] if time >= range[0] && time <= range[1]
  end

···

--
Peter Hicks <peter.hicks@poggs.co.uk>

...and I have no idea how 'Renages' ended up in the subject!

···

--
Peter Hicks <peter.hicks@poggs.co.uk>

It is very much a simple mapping, it just isn't a 1:1 mapping anymore. All you need to do is figure out which hour and half hour of the day it is, and return the code for that.

Given a time t, `t.min / 30` gives you 0 or 1 based on which half hour you're in. t.hour gives you 0 to 23 based on which hour you're in. So:

    t.hour * 2 + (t.hour / 30)

Gives you a number from 0 to 47. From there you can either look it up from a pre-populated array or hash or whatever...

xlate = "00112233445566ABCDEFGHIJKLMNOPQRSTUVWXYZ778899".split(//)

t = Time.now
p [t.hour, t.min] # => [14, 10]
p xlate[t.hour * 2 + (t.hour / 30)] # => "O"

···

On Jul 2, 2011, at 13:37 , Peter Hicks wrote:

I have a requirement to translate a time between 0000 and 2359 in to a
single character 'interval ID' based on the time. For example, if the
time is between 0000 and 0059, '0' should be returned, if it's between
0100 and 0159, '1' should be return. The problem is that 0700-0729
should return 'A', 0730-0759 should return 'B', i.e. it's not a simple
mapping.

Afternoon,

All,

I have a requirement to translate a time between 0000 and 2359 in to a
single character 'interval ID' based on the time. For example, if the
time is between 0000 and 0059, '0' should be returned, if it's between
0100 and 0159, '1' should be return. The problem is that 0700-0729
should return 'A', 0730-0759 should return 'B', i.e. it's not a simple
mapping.

I have the following, but I can't help thinking there's a much more
efficient way of doing it - can anyone advise, as I'm a little stuck!

xlate = [ [ '0000', '0059', '0' ], [ '0100', '0159', '1' ],
           [ '0200', '0259', '2' ], [ '0300', '0359', '3' ],
           [ '0400', '0459', '4' ], [ '0500', '0559', '5' ],
           [ '0600', '0659', '6' ], [ '0700', '0729', 'A' ],
           [ '0730', '0759', 'B' ], [ '0800', '0829', 'C' ],
           [ '0830', '0859', 'D' ], [ '0900', '0929', 'E' ],
           [ '0930', '0959', 'F' ], [ '1000', '1029', 'G' ],
           [ '1030', '1059', 'H' ], [ '1100', '1129', 'I' ],
           [ '1130', '1159', 'J' ], [ '1200', '1229', 'K' ],
           [ '1230', '1259', 'L' ], [ '1300', '1329', 'M' ],
           [ '1330', '1359', 'N' ], [ '1400', '1429', 'O' ],
           [ '1430', '1459', 'P' ], [ '1500', '1529', 'Q' ],
           [ '1530', '1559', 'R' ], [ '1600', '1629', 'S' ],
           [ '1630', '1659', 'T' ], [ '1700', '1729', 'U' ],
           [ '1730', '1759', 'V' ], [ '1800', '1829', 'W' ],
           [ '1830', '1859', 'X' ], [ '1900', '1959', 'Y' ],
           [ '2000', '2059', 'Z' ], [ '2100', '2159', '7' ],
           [ '2200', '2259', '8' ], [ '2300', '2359', '9' ] ]

xlate.each do |range|
   return range[2] if time >= range[0] && time <= range[1]
end

How about this

#Setup a string with all 48 options (splitting into half hours)
results = "00112233445566ABCDEFGHIJKLMNOPQRSTUVWXYYZZ778899"

#Convert our time into which of the 48 half hour slots it fits
time = '1734'
slot = (time[0..1].to_i * 60 + time[2..3].to_i) / 30 #> 35

#Return the result for the slot
results[slot] #> V

John

···

On Sat, Jul 2, 2011 at 1:37 PM, Peter Hicks <peter.hicks@poggs.co.uk> wrote:

You just need to check from the "end" on back and pick the first one that matches.

  xlate = [ [ '0000', '0' ], [ '0100', '1' ], [ '0200', '2' ], [ '0300', '3' ],
            [ '0400', '4' ], [ '0500', '5' ], [ '0600', '6' ], [ '0700', 'A' ],
            [ '0730', 'B' ], [ '0800', 'C' ], [ '0830', 'D' ], [ '0900', 'E' ],
            [ '0930', 'F' ], [ '1000', 'G' ], [ '1030', 'H' ], [ '1100', 'I' ],
            [ '1130', 'J' ], [ '1200', 'K' ], [ '1230', 'L' ], [ '1300', 'M' ],
            [ '1330', 'N' ], [ '1400', 'O' ], [ '1430', 'P' ], [ '1500', 'Q' ],
            [ '1530', 'R' ], [ '1600', 'S' ], [ '1630', 'T' ], [ '1700', 'U' ],
            [ '1730', 'V' ], [ '1800', 'W' ], [ '1830', 'X' ], [ '1900', 'Y' ],
            [ '2000', 'Z' ], [ '2100', '7' ], [ '2200', '8' ], [ '2300', '9' ],
            ].reverse
# Note the .reverse here

time = Time.now.strftime('%H%M')
xlate.detect{|(start,code)| time >= start}

Then you can vary the start times and not be concerned about the "breaks" in the mapping or whether there is a 30-minute boundary. (And not build an 60x24 entry string or array of minutes even though that might be more efficient depending on how many lookups you need to do.)

-Rob

Rob Biedenharn
Rob@AgileConsultingLLC.com http://AgileConsultingLLC.com/
rab@GaslightSoftware.com http://GaslightSoftware.com/

···

On Jul 2, 2011, at 4:37 PM, Peter Hicks wrote:

All,

I have a requirement to translate a time between 0000 and 2359 in to a
single character 'interval ID' based on the time. For example, if the
time is between 0000 and 0059, '0' should be returned, if it's between
0100 and 0159, '1' should be return. The problem is that 0700-0729
should return 'A', 0730-0759 should return 'B', i.e. it's not a simple
mapping.

I have the following, but I can't help thinking there's a much more
efficient way of doing it - can anyone advise, as I'm a little stuck!

xlate = [ [ '0000', '0059', '0' ], [ '0100', '0159', '1' ],
           [ '0200', '0259', '2' ], [ '0300', '0359', '3' ],
           [ '0400', '0459', '4' ], [ '0500', '0559', '5' ],
           [ '0600', '0659', '6' ], [ '0700', '0729', 'A' ],
           [ '0730', '0759', 'B' ], [ '0800', '0829', 'C' ],
           [ '0830', '0859', 'D' ], [ '0900', '0929', 'E' ],
           [ '0930', '0959', 'F' ], [ '1000', '1029', 'G' ],
           [ '1030', '1059', 'H' ], [ '1100', '1129', 'I' ],
           [ '1130', '1159', 'J' ], [ '1200', '1229', 'K' ],
           [ '1230', '1259', 'L' ], [ '1300', '1329', 'M' ],
           [ '1330', '1359', 'N' ], [ '1400', '1429', 'O' ],
           [ '1430', '1459', 'P' ], [ '1500', '1529', 'Q' ],
           [ '1530', '1559', 'R' ], [ '1600', '1629', 'S' ],
           [ '1630', '1659', 'T' ], [ '1700', '1729', 'U' ],
           [ '1730', '1759', 'V' ], [ '1800', '1829', 'W' ],
           [ '1830', '1859', 'X' ], [ '1900', '1959', 'Y' ],
           [ '2000', '2059', 'Z' ], [ '2100', '2159', '7' ],
           [ '2200', '2259', '8' ], [ '2300', '2359', '9' ] ]

xlate.each do |range|
   return range[2] if time >= range[0] && time <= range[1]
end

-- Peter Hicks <peter.hicks@poggs.co.uk>

I figured it was a weird typo for "ranges".

···

On Sun, Jul 03, 2011 at 05:40:42AM +0900, Peter Hicks wrote:

...and I have no idea how 'Renages' ended up in the subject!

--
Chad Perrin [ original content licensed OWL: http://owl.apotheon.org ]

John, Ryan, thank you so much - a brilliantly simple and minimal idea
that I didn't even think of.

Peter

···

On Sun, 2011-07-03 at 06:12 +0900, Ryan Davis wrote:

It is very much a simple mapping, it just isn't a 1:1 mapping anymore. All you need to do is figure out which hour and half hour of the day it is, and return the code for that.

--
Peter Hicks <peter.hicks@poggs.co.uk>

simple benchmark:

real math 1.180000 0.000000 1.180000 ( 1.193925)
table lookup 13.460000 0.040000 13.500000 ( 14.111571)

···

On Jul 5, 2011, at 10:34 , Rob Biedenharn wrote:

You just need to check from the "end" on back and pick the first one that matches.

xlate = [ [ '0000', '0' ], [ '0100', '1' ], [ '0200', '2' ], [ '0300', '3' ],
          [ '0400', '4' ], [ '0500', '5' ], [ '0600', '6' ], [ '0700', 'A' ],
          [ '0730', 'B' ], [ '0800', 'C' ], [ '0830', 'D' ], [ '0900', 'E' ],
          [ '0930', 'F' ], [ '1000', 'G' ], [ '1030', 'H' ], [ '1100', 'I' ],
          [ '1130', 'J' ], [ '1200', 'K' ], [ '1230', 'L' ], [ '1300', 'M' ],
          [ '1330', 'N' ], [ '1400', 'O' ], [ '1430', 'P' ], [ '1500', 'Q' ],
          [ '1530', 'R' ], [ '1600', 'S' ], [ '1630', 'T' ], [ '1700', 'U' ],
          [ '1730', 'V' ], [ '1800', 'W' ], [ '1830', 'X' ], [ '1900', 'Y' ],
          [ '2000', 'Z' ], [ '2100', '7' ], [ '2200', '8' ], [ '2300', '9' ],
          ].reverse
# Note the .reverse here

time = Time.now.strftime('%H%M')
xlate.detect{|(start,code)| time >= start}

You just need to be aware that the approach works only as long as the
shortest interval length is 30 minutes AND all interval endpoints are
aligned with this interval length. If you need to be able to easily
change any of those intervals in between you need to change the whole
logic.

As worst case fallback you could assume minimal resolution 1 minute
and use your original input to generate an String of length 1440 (= 24
* 60, minutes per day) from it for efficient lookup. Then you have
xlate[t.hour * 60 + t.min].

Kind regards

robert

···

On Sun, Jul 3, 2011 at 11:21 AM, Peter Hicks <peter.hicks@poggs.co.uk> wrote:

On Sun, 2011-07-03 at 06:12 +0900, Ryan Davis wrote:

It is very much a simple mapping, it just isn't a 1:1 mapping anymore. All you need to do is figure out which hour and half hour of the day it is, and return the code for that.

John, Ryan, thank you so much - a brilliantly simple and minimal idea
that I didn't even think of.

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/