Java相当于Perl的哈希值

时间:2011-01-22 16:45:26

标签: java perl data-structures hash

由于超级灵活和方便,我一直在使用很多Perl哈希。 例如,在Perl中,我可以执行以下操作:

$hash{AREA_CODE}->{PHONE}->{STREET_ADDR}

我想知道如何用Java完成同样的事情,我想这与HashMap有关?

谢谢,

8 个答案:

答案 0 :(得分:18)

  

由于超级灵活和方便,我一直在使用很多Perl哈希。例如,在Perl中我可以执行以下操作:       $hash{AREA_CODE}->{PHONE}->{STREET_ADDR}   我想知道如何用Java完成同样的事情,我想这与HashMap有关?

近似以下Perl代码的Java代码:

my %hash;
$hash{AREA_CODE}{PHONE}{STREET_ADDR} = "221B Baker Street";
printf "Street address is %s\n", $hash{AREA_CODE}{PHONE}{STREET_ADDR};

HashMap<String, HashMap<String, HashMap<String, String>>> hash =
    new HashMap<String, HashMap<String, HashMap<String, String>>>();

hash.put("AREA_CODE", new HashMap<String, HashMap<String, String>>());
hash.get("AREA_CODE").put("PHONE", new HashMap<String, String>());
hash.get("AREA_CODE").get("PHONE").put("STREET_ADDR", "221B Baker Street");

System.out.printf("Street address is %s\n",
    hash.get("AREA_CODE").get("PHONE").get("STREET_ADDR"));

那不是特别吗? :)

我说'近似'有很多原因。其中之一就是在Java中,你只会因为想要在Java的下一行上完成相当于这个非常直接的Perl代码而对极端中风这一点感到沮丧:

$hash{AREA_CODE}{PREFIX} = 800;

如果你想要Perl在这样的事情上的灵活性和便利性,Java根本就不会给你。更糟糕的是,它的党派通常会因为表达这种愿望而谴责你。

答案 1 :(得分:5)

请参阅Map界面及其实现,特别是HashMap

请注意Java没有Perl的自动生成(方便但dangerous功能),以便

hash.get("areaCode").get("phone").get("streetAdr")
如果例如get(phone)返回null,

将抛出异常。 还要注意你不应该为具有固定名称(“属性”)的东西使用哈希,你应该用它的getter和setter定义你自己的类。

答案 2 :(得分:5)

首先,您的具体示例($hash{AREA_CODE}->{PHONE}->{STREET_ADDR}),使用硬编码字符串作为哈希键,并不像Michael Carman所指出的那样在Java中真正有用的数据结构 - 它应该存储为一个类属性(说实话,它在概念上是一个糟糕的数据结构 - 像这样的数据更可能是一组手机,而不是手机的哈希)。

其次,假设你实际上意味着$hash{$AREA_CODE}->{$PHONE}->{$STREET_ADDR},看起来每个人的Java代码到目前为止都没有实现通用的等效代码 - 代码都假设Java哈希是为了存储示例而新初始化的,或者是完全填充的,用于检索示例(换句话说,正如 leonbloy 的回答所指出的那样,缺少自动修复功能)。

正确的代码mimiquing autovivification是:

// This method will ensure that hash-of-hash-of-hashes structure exists of a given set of 3 keys.
public HashMap<String, HashMap<String, HashMap<String, Object>>>
 autovivification_3rd_level (
           HashMap<String, HashMap<String, HashMap<String, Object>>> hash
         , String AREA_CODE, String PHONE, String STREET_ADDR) {
    if (hash == null) {
        hash = new HashMap<String, HashMap<String, HashMap<String, Object>>>();
    }
    if (!hash.contains(AREA_CODE) || hash.get(AREA_CODE) == null) {
        hash.put(new HashMap<String, HashMap<String, Object>>());
    }
    HashMap<String, HashMap<String, Object>> AREA_CODE_hash
         = (HashMap<String, HashMap<String, Object>>) hash.get(AREA_CODE);
    if (!AREA_CODE_hash.contains(PHONE) || AREA_CODE_hash.get(PHONE) == null) {
        AREA_CODE_hash.put(new HashMap<String, Object>());
    }
    return hash;
}

////////////////////////////////////////////////////////////////////////////////////    

// Equivalent to Perl's "$hash{$AREA_CODE}->{$PHONE}->{$STREET_ADDR} = value;"
public Object put_3d_level_hash(
          HashMap<String, HashMap<String, HashMap<String, Object>>> hash
        , String AREA_CODE, String PHONE, String STREET_ADDR,
        , Object value) {
    hash = autovivification_3rd_level(hash, AREA_CODE, PHONE, STREET_ADDR);
    return hash.get(AREA_CODE).get(PHONE).put(STREET_ADDR, value);
}
put_3d_level_hash(hash, AREA_CODE, PHONE, STREET_ADDR, obj);

////////////////////////////////////////////////////////////////////////////////////    

// Equivalent to Perl's "$var = $hash{$AREA_CODE}->{$PHONE}->{$STREET_ADDR}"
public Object get_3d_level_hash(HashMap<String, HashMap<String, HashMap<String, Object>>> hash
                       , String AREA_CODE, String PHONE, String STREET_ADDR) {
    hash = autovivification_3rd_level(hash, AREA_CODE, PHONE, STREET_ADDR);
    return hash.get(AREA_CODE).get(PHONE).get(STREET_ADDR);
}
Object obj = get_3d_level_hash(hash, AREA_CODE, PHONE, STREET_ADDR);

答案 3 :(得分:2)

Java有哈希,但由于强类型,它们不像Perl中的哈希那么灵活。多维哈希更难以使用。在Perl中,您可以声明一个哈希并让autovivification根据需要创建嵌套哈希。

my %hash;
$hash{a}{b} = 1;

在Java中,你必须预先声明它是哈希哈希。

Map<String,Map<String,Integer>> hash = new HashMap<String,HashMap<String,Integer>>();
hash.put("a", new HashMap<String, Integer>());
hash.get("a").put("b", new Integer(1));

对于每个额外的维度,您需要在声明中添加另一个Map<K,V>嵌套。除了单调乏味之外,这还不是很好。

答案 4 :(得分:1)

如果哈希键是常量,为什么不hash.getAreaCode().getPhone().getStreetAddr()呢?请记住,您的getter或构造函数都需要处理默认值生成。

答案 5 :(得分:1)

您可以轻松地对哈希进行子类化,以添加一个为您自动生成的方法。

来自:$hash{AREA_CODE}->{PHONE}->{STREET_ADDR}

收件人:hash.vivifyingGet(areaCode).put(phone, streetAddr)

假设我用:

创建了哈希
/**
  * A two-level autovivifying hashmap of X and Y to Z. Provides
  * a new method #vivifyingGet(X) which creates the next level of hash.
  */
Map<AreaCode, Map<Phone, StreetAddr>> hash =
    new HashMap<AreaCode, Map<Phone, StreetAddr>>() {
    /**
      * Convenience method to get or create the next level of hash.
      * @param key the first level key
      * @return the next level map
      */
    public Map<Phone, StreetAddr> vivifyingGet(Phone key) {
        if (containsKey(key)) {
            return get(key);
        } else {
            Map<Phone, StreetAddr> = hash = new HashMap<Phone, StreetAddr>();
            put(key, hash);
            return hash;
        }
    }
};

答案 6 :(得分:0)

我在工作中错过了很多perl哈希,并使用哈希类做了一些丑陋的变通办法。

上周我有一个想法在一个PerlMap类中实现整个事情,它使用分隔符来访问对象,最重要的是Lists zu访问子集。

它适用于map.get(code:street:phone)map.put(code:street:phone,"123456789")。要获取phonenumber列表,只需使用map.getList(code:street)即可。

我刚刚开始,但现在在我的项目中使用。它没有复杂性的限制:-)你可以选择免费的分隔符。我将所有内容放在http://www.jdeer.org下。玩得开心。

答案 7 :(得分:-4)

如果你想要这种灵活性但仍然在JVM中运行,你可能会想要使用Groovy。 tchrist喜欢忽略Java强类型而不是像Perl或PHP这样的动态类型语言 - 并且也喜欢忽略Java在运行时速度快一个数量级,但这只是我的“党派”,显然。