1

I want to assign a String/behavior to each interval [0,1), [1,2), ..., [4, 5]. For a general enum class we can assign just an integer to each String:

public enum Behavior {
    SMILE(4),
    FUNNY(3),
    NORMAL(2),
    SAD(1),
    CRY(0);

    final int behaviorCode;

    BehaviorCode(int behaviorCode) {
        this.behaviorCode= behaviorCode;
    }
}

Is that possible to have something like SMILE((3,4]) in Java? i.e. return SMILE for 3<x<= 4.

I know that one can write a similar method inside the activity/fragment using if-else. But I like to do that with enum or at least in less code.

Federico klez Culloca
  • 26,308
  • 17
  • 56
  • 95

3 Answers3

4

This is in Kotlin, but you can do something similar in Java with a static function and member collection.

Keep a sorted list of the items, then search it when an item is requested in the companion object function.

enum class Behavior(val behaviorCode: Int) {
    SMILE(4),
    FUNNY(3),
    NORMAL(2),
    SAD(1),
    CRY(0);

    companion object {
        private val sortedByCode = Behavior.values().sortedBy(Behavior::behaviorCode)

        fun forCode(code: Int): Behavior? = sortedByCode.firstOrNull { it.behaviorCode >= code }
    }
}
Tenfour04
  • 83,111
  • 11
  • 94
  • 154
  • My question is how to assign an interval to a String using enum. does your post answer my question? – user21193451 Aug 29 '23 at 16:39
  • 1
    What do you mean by "assign to a String"? Do you mean you want a function that has an input parameter of an Int and returns a range formatted as a String? No Behavior return value? My answer solves the request you had " i.e. return SMILE for 3 – Tenfour04 Aug 29 '23 at 16:42
  • That is what I want (return SMILE for 3 – user21193451 Aug 29 '23 at 16:54
  • `Behavior(3.5)` will return `SMILE`? but it accept just int values.!! – user21193451 Aug 29 '23 at 16:58
  • 1
    The logic will do what you're describing without separately defined ranges. It works because we keep the items sorted, so the sorted list acts as the definition of the ranges. If you want to accept doubles, you can change it to `code: Double` and it should still work. – Tenfour04 Aug 29 '23 at 17:23
1

For Java, you can use a Predicate<Double>. That would be the simplest way.

By the way, I am assuming that your intervals do not overlap. If they do, provide clarification via an edit to your post, and then comment on my answer, notifying me.

   public enum Behavior 
   {
      
      SMILE(4),
      FUNNY(3),
      NORMAL(2),
      SAD(1),
      CRY(0),
      ;
   
      final int behaviorCode;
      private final java.util.function.Predicate<Double> range;
   
      Behavior(final int behaviorCode) 
      {
      
         this.behaviorCode = behaviorCode;
         this.range = x -> this.behaviorCode < x && x <= this.behaviorCode + 1;
      
      }
      
      public static Behavior forValue(final double value)
      {
      
         for (final Behavior each : Behavior.values())
         {
         
            if (each.range.test(value))
            {
            
               return each;
            
            }
         
         }
         
         throw new IllegalArgumentException("value does not match any of the Behaviour Codes! value = " + value);
      
      }
   
   }

If I run it, here is how it goes.

Behavior.forValue(5)      ---> Behavior.SMILE
Behavior.forValue(4.9999) ---> Behavior.SMILE
Behavior.forValue(4.0001) ---> Behavior.SMILE
Behavior.forValue(4)      ---> Behavior.FUNNY
Behavior.forValue(4.0)    ---> Behavior.FUNNY
Behavior.forValue(3.9999) ---> Behavior.FUNNY
Behavior.forValue(3)      ---> Behavior.NORMAL
Behavior.forValue(2)      ---> Behavior.SAD
Behavior.forValue(1)      ---> Behavior.CRY
Behavior.forValue(0)      ---> java.lang.IllegalArgumentException: value does not match any of the Behaviour Codes! value = 0.0
Behavior.forValue(5.0001) ---> java.lang.IllegalArgumentException: value does not match any of the Behaviour Codes! value = 5.0001
Behavior.forValue(6)      ---> java.lang.IllegalArgumentException: value does not match any of the Behaviour Codes! value = 6.0
Behavior.forValue(42)     ---> java.lang.IllegalArgumentException: value does not match any of the Behaviour Codes! value = 42.0
davidalayachew
  • 1,279
  • 1
  • 11
  • 22
1

If your intervals are adjacent, you can treat each value as a ceiling with another field to indicate whether it's inclusive or exclusive:

public enum Behavior {
    SMILE(5, true),
    FUNNY(4, true),
    NORMAL(3, true),
    SAD(2, false),
    CRY(1, false);

    public static Behavior find(double value) {
        return Arrays.stream(values())
                .sorted(Comparator.comparingDouble(b -> b.ceil))
                .filter(b -> b.inclusive ? value <= b.ceil : value < b.ceil)
                .findFirst()
                .orElse(null);
    }

    private final double ceil;
    private final boolean inclusive;

    Behavior(double ceil, boolean inclusive) {
        this.ceil = ceil;
        this.inclusive = inclusive;
    }
}

If you need more flexibility, take a look at Guava's Range and RangeMap.

shmosel
  • 49,289
  • 6
  • 73
  • 138