Search code examples
gocoding-style

Clean way of writing several nested if-else with number ranges in Go


This piece of code is effective but I don't feel good about it when I read it. I'm finding trouble refactoring into something more legible or short. Breaking the code into several if-return doesn't seem to be of great help here. Tips? Thanks!

if t < 0 {
    r = 0
} else if t >= 0 && t < 7.5 {
    if m >= 0 && m < 0.125 {
        r = 1
    } else {
        r = 2
    }
} else if t >= 7.5 && t < 10 {
    if m >= 0 && m < 0.125 {
        r = 1
    } else {
        r = 4
    }
} else if t >= 10 && t < 20 {
    if m >= 0 && m < 0.125 {
        r = 1
    } else if m >= 0.125 && m < 0.25 {
        r = 3
    } else {
        r = 4
    }
} else if t >= 20 && t < 22.5 {
    if m >= 0 && m < 0.125 {
        r = 7
    } else if m >= 0.125 && m < 0.375 {
        r = 3
    } else {
        r = 4
    }
} else if t >= 22.5 && t < 27.5 {
    if m >= 0 && m < 0.125 {
        r = 7
    } else if m >= 0.125 && m < 0.625 {
        r = 5
    } else {
        r = 6
    }
} else if t >= 27.5 {
    if m >= 0 && m < 0.25 {
        r = 7
    } else if m >= 0.25 && m < 0.625 {
        r = 5
    } else {
        r = 6
    }
}

Solution

  • Looking at the values, you can encode the range checks with some data structures:

    type Rng struct {
       From,To float64
       V int
    }
    
    func (r Rng) In(val float64) bool { return val>=r.From && val<r.To }
    
    type ARange struct {
       T Rng
       M []Rng  
       Def int // Default value for r if none of the M ranges match
    }
    
    var ranges=[]ARange{ {T:Rng{0,7.5}, M:[]Rng{ {0,0.125,1} }, Def: 2 },
      ...
    

    Then, write a for-loop that goes through each element of ranges and checks t and m to see if there are any matches.