Get rid of ugly if statements

后端 未结 25 1975
借酒劲吻你
借酒劲吻你 2020-12-02 05:59

I have this ugly code:

if ( v > 10 ) size = 6;
if ( v > 22 ) size = 5;
if ( v > 51 ) size = 4;
if ( v > 68 ) size = 3;
if ( v > 117 ) size = 2         


        
相关标签:
25条回答
  • 2020-12-02 06:38

    How about such approach:

    int getSize(int v) {
        int[] thresholds = {145, 117, 68, 51, 22, 10};
    
        for (int i = 0; i < thresholds.length; i++) {
            if (v > thresholds[i]) return i+1;
        }
        return 1;
    }
    

    Functionally: (Demonstrated in Scala)

    def getSize(v: Int): Int = {
      val thresholds = Vector(145, 117, 68, 51, 22, 10)
      thresholds.zipWithIndex.find(v > _._1).map(_._2).getOrElse(0) + 1
    }
    
    0 讨论(0)
  • 2020-12-02 06:38

    There are a ton of answers and suggestions here but I honestly don't see any of them "prettier" or "more elegant" than the original method.

    If you had dozens or HUNDREDS of iterations to check then I could easily see going to some for loop but honestly, for the handful of comparisons you had, stick with the if's and move on. It's not that ugly.

    0 讨论(0)
  • 2020-12-02 06:38
    return (v-173) / -27;
    
    0 讨论(0)
  • 2020-12-02 06:40

    This is my code sample, using SortedSet. You initialise boundaries once.

    SortedSet<Integer> boundaries = new SortedSet<Integer>;
    
    boundaries.add(10);
    
    boundaries.add(22);
    
    boundaries.add(51);
    
    boundaries.add(68);
    
    boundaries.add(117);
    
    boundaries.add(145);
    

    Then use it subsequently this way for multiple values of v (and initialised size)

    SortedSet<Integer> subset =  boundaries.tailSet(v);
    if( subset.size() != boundaries.size() )
      size = subset.size() + 1;
    
    0 讨论(0)
  • 2020-12-02 06:41

    I have one more version for you. I don't really think it's the best one because it adds unnecessary complexity in the name of "performance" when I'm 100% sure this function will never be a performance hog (unless someone is calculating size in a tight loop a million times ...).

    But I present it just because I thought performing a hard-coded binary search to be sort of interesting. It doesn't look very binary-y because there aren't enough elements to go very deep, but it does have the virtue that it returns a result in no more than 3 tests rather than 6 as in the original post. The return statements are also in order by size which would help with understanding and/or modification.

    if (v > 68) {
       if (v > 145) {
          return 1
       } else if (v > 117) {
          return 2;
       } else {
          return 3;
       }
    } else {
       if (v > 51) {
          return 4;
       } else if (v > 22) {
          return 5;
       } else {
          return 6;
       }
    }
    
    0 讨论(0)
  • 2020-12-02 06:41

    Here is an object-oriented solution, a class called Mapper<S,T> that maps values from any type that implements comparable to any target type.

    Syntax:

    Mapper<String, Integer> mapper = Mapper.from("a","b","c").to(1,2,3);
    
    // Map a single value
    System.out.println(mapper.map("beef")); // 2
    
    // Map a Collection of values
    System.out.println(mapper.mapAll(
        Arrays.asList("apples","beef","lobster"))); // [1, 2, 3]
    

    Code:

    public class Mapper<S extends Comparable<S>, T> {
    
        private final S[] source;
        private final T[] target;
    
        // Builder to enable from... to... syntax and
        // to make Mapper immutable
        public static class Builder<S2 extends Comparable<S2>> {
            private final S2[] data;
            private Builder(final S2[] data){
                this.data = data;
            }
            public <T2> Mapper<S2, T2> to(final T2... target){
                return new Mapper<S2, T2>(this.data, target);
            }
        }
    
    
        private Mapper(final S[] source, final T[] target){
            final S[] copy = Arrays.copyOf(source, source.length);
            Arrays.sort(copy);
            this.source = copy;
            this.target = Arrays.copyOf(target, target.length);
        }
    
        // Factory method to get builder
        public static <U extends Comparable<U>, V> Builder<U> from(final U... items){
            return new Builder<U>(items);
        }
    
        // Map a collection of items
        public Collection<T> mapAll(final Collection<? extends S> input){
            final Collection<T> output = new ArrayList<T>(input.size());
            for(final S s : input){
                output.add(this.map(s));
            }
            return output;
        }
    
        // map a single item
        public T map(final S input){
            final int sourceOffset = Arrays.binarySearch(this.source, input);
            return this.target[
                Math.min(
                    this.target.length-1,
                    sourceOffset < 0 ? Math.abs(sourceOffset)-2:sourceOffset
                )
            ];
        }
    }
    

    Edit: finally replaced the map() method with a more efficient (and shorter) version. I know: a version that searches partitions would still be faster for large arrays, but sorry: I'm too lazy.

    If you think this is too bloated, consider this:

    1. It contains a builder that lets you create the Mapper using varargs syntax. I'd say that's a must-have for usability
    2. It contains both a single item and a collection mapping method
    3. It's immutable and hence thread safe

    Sure, all of these features could be easily removed, but the code would be less complete, less usable or less stable.

    0 讨论(0)
提交回复
热议问题