【问题标题】:Checking if a String is contained in an Enum Set in O(1)检查字符串是否包含在 O(1) 中的枚举集中
【发布时间】:2018-08-01 10:32:10
【问题描述】:

假设我有一个像下面这样的枚举:

public enum Utils {
    UTIL_1, UTIL_2, ... UTIL_n
}

现在,我有Set<Utils> myUtils,其中包含一堆这些枚举条目。其他一些模块(我没有任何控制权)给我一个这样的实用程序名称(比如“UTIL_i”)作为字符串。我需要检查它是否包含在集合myUtils 中。有没有办法在 O(1) 中执行此操作?我了解,我可以将集合更改为一组字符串,然后对其执行 .contains(),但我想保留它作为最后的手段。

更新: 按照答案中的建议,我尝试了一个小实验。我创建了一个小代码 sn-p 来生成一个包含固定大小枚举的 java 文件。我尝试使用大小 1000、2500、5000。大小为 10000 的枚举向我显示了 Eclipse 中的错误 The code for the static initializer is exceeding the 65535 bytes limit,对此进行了解释 here。我创建了一个 Set myUtils 并将 Enum 中的所有元素推送到该集合。对于这些不同大小的myUtils,我执行了 1000 次 sn-p,看起来像 myUtils.contains(Utils.valueOf(<elementName>))。该代码 sn-p 的平均执行时间(以 ms 为单位)如下所示:

枚举大小=1000

UTIL_1     search duration = 1704ms
UTIL_500   search duration = 2316ms
UTIL_1000  search duration = 1732ms

枚举大小=2500

UTIL_1     search duration = 2326ms
UTIL_1250  search duration = 1886ms
UTIL_2500  search duration = 1860ms

枚举大小=5000

UTIL_1     search duration = 2569ms
UTIL_2500  search duration = 2709ms
UTIL_5000  search duration = 2361ms

它清楚地显示了Enum.valueOf(String element) 的平均执行时间随着枚举的大小而增加,但我不确定这个方法的时间复杂度。

【问题讨论】:

    标签: java enums


    【解决方案1】:

    您可以通过Utils util = Utils.valueOf(String) 将String 转换为实际的Utils 成员,然后通过myUtils.contains(util) 检查它是否包含在集合中,其中AFAIK 是O(1) 操作。

    当然你应该检查异常,以防你得到的字符串实际上不对应任何Utils。在您的示例中,它不会,因为它应该像枚举名称一样大写。

    public enum Utils {
        UTIL_1, UTIL_2, ... UTIL_n
    }
    
    //...
    
    String utilName = someOtherModuleRoutine();
    try {
        if (myUtils.contains(Utils.valueOf(utilName))) {
            // found!
        } else {
            // not found :(
        }
    } catch (IllegalArgumentException e) {
        // utilName is not an actual Utils name
    }
    

    【讨论】:

    • 啊,谢谢。那个“Utils_1”是我忽略的,我打算用大写。我将编辑我的问题以反映这一点。
    【解决方案2】:

    其中一个选择是使用enumvalueOf 方法,但它的时间复杂度取决于您将使用的输入。

    如果您的大多数 输入都不可转换Utils 枚举,那么制作 set 并使用 contains 方法是最好的方法,因为 valueOf 方法不适用于以下值是不可兑换的。

    参考资料: Java enum valueOf efficiency

    【讨论】:

      【解决方案3】:

      我建议您扩展 Enum 以添加来自其他模块的字符串标识符。另外,我将编写一个方法来将 String 转换为 Util 枚举。

      public enum Utils {
      
          UTIL_1("Utils_1"),
      
          UTIL_2("Utils_2"),
      
          UTIL_3("Utils_3");
      
          private final String name;
      
          private Utils(final String name) {
              this.name = name;
          }
      
          public String getName() {
              return this.name;
          }
      
          public static Utils of(final String name) {
              if (name != null) {
                  for (final Utils util : Utils.values()) {
                      if (util.getName().equals(name)) {
                          return util;
                      }
                  }
              }
              return null;
          }
      
      }
      

      要使用枚举集合,您应该使用 EnumSet 或 EnumMap。然后你可以这样做:

      public static void main(final String[] args) {
          final String utilName = "Utils_1";
          final Utils utilFromModule = Utils.of(utilName);
      
          final Set<Utils> utils = EnumSet.of(Utils.UTIL_1, Utils.UTIL_2);
          utils.contains(utilFromModule);
      }
      

      【讨论】:

      • 我已经更新了我的问题以反映一个小的修改。在这种情况下,我认为操作是 O(n),因为 for 循环。
      猜你喜欢
      • 1970-01-01
      • 2011-06-23
      • 1970-01-01
      • 2014-08-09
      • 1970-01-01
      • 2020-11-29
      • 2012-08-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多