由于其超级灵活性和方便性,我一直在大量使用Perl哈希表。例如,在Perl中,我可以执行以下操作:
$hash{AREA_CODE}->{PHONE}->{STREET_ADDR}
我想知道如何用Java实现相同的功能,我猜这可能与HashMap有关?
谢谢。
由于其超级灵活性和方便性,我一直在大量使用Perl哈希表。例如,在Perl中,我可以执行以下操作:
$hash{AREA_CODE}->{PHONE}->{STREET_ADDR}
我想知道如何用Java实现相同的功能,我猜这可能与HashMap有关?
谢谢。
由于其超级灵活性和便捷性,我一直在使用很多Perl哈希表。例如,在Perl中,我可以这样做:
$hash {AREA_CODE} -> {PHONE} -> {STREET_ADDR}
我想知道如何在Java中实现同样的功能,我猜这与HashMap有关?
下面是 Java 代码,它近似地等同于上述 Perl 代码:
my %hash;
$hash{AREA_CODE}{PHONE}{STREET_ADDR} = "221B Baker Street";
printf "Street address is %s\n", $hash{AREA_CODE}{PHONE}{STREET_ADDR};
is
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中,你只是想在下一行代码中执行与这个完全简单的Perl代码等价的操作,你就会感到非常沮丧,甚至到极点发怒。
$hash{AREA_CODE}{PREFIX} = 800;
如果你想在这方面获得像Perl那样的灵活性和便利性,Java是无法满足你的。更糟糕的是,Java的支持者经常会指责你甚至表达这样的愿望。
$hash{AREA_CODE}->{PHONE}->{STREET_ADDR}
),使用硬编码字符串作为哈希键,在Java中并不是一个真正有用的数据结构,正如Michael Carman所指出的那样 - 应该将其存储为具有属性的类(而且说实话,这个数据结构在概念上是一个糟糕的数据结构 - 这种数据更可能是电话数组,而不是电话哈希)。$hash{$AREA_CODE}->{$PHONE}->{$STREET_ADDR}
,到目前为止,似乎所有人的Java代码都没有实现通用等价代码 - 代码都假定Java哈希是新初始化的用于存储示例或完全填充的用于检索示例(换句话说,就像leonbloy的答案所指出的,缺少自动vivification功能)。// 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);
O(1)
的访问/存储时间(作为真正的哈希映射),而实现Map接口的通用Java类可能没有这个特性。 - DVKArrayList<HashMap<String, String>> data = new ArrayList<HashMap<String, String>>(capacity, 1);
来获得 O(1),然后将任何键值对添加到哈希映射中。 - MarcusJava有哈希表,但由于强类型的限制,其灵活性不如Perl中的哈希表。多维哈希表更难处理。在Perl中,你可以声明一个哈希表,并让自动化创建嵌套哈希表。
my %hash;
$hash{a}{b} = 1;
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>
。除了繁琐之外,这并不是非常面向对象的。
$hash{$a}{$b}{$c}
)而言,如果该说法适用,则同样必须适用于多维普通数组(如 $array[$i][$j][$k]
),甚至也适用于单下标数组(如 $ARGV[$n]
)。为了笨拙地使用过度抽象的面向对象构造而避免使用下标聚合是浪费大家时间的行为。Java 无法像对待数组一样将哈希作为一等公民来处理,这只是 Java 无数不合理烦人之一。即使 C++(最终)也设法解决了这个问题。 - tchristput()
上的下标。正确的写法应该是hash.get("a").put("b", new Integer(1));
。 - tchristHashMap<String, HashMap<String, Integer>> hash = new HashMap<String, HashMap<String, Integer>>();
。Java 真有趣! - tchrist$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;
}
}
};
hash.getAreaCode().getPhone().getStreetAddr()
?请记住,您的getter或构造函数需要处理默认值生成。我在工作中非常想念Perl哈希表,并使用哈希类做了一些丑陋的解决方案。
上周我有一个想法,将整个东西实现在一个PerlMap
类中,该类使用分隔符访问对象,最重要的是使用Lists
来访问子集。
使用map.get(code:street:phone)
和map.put(code:street:phone,"123456789")
可以很好地工作。要获取电话号码列表,只需使用map.getList(code:street)
。
我刚刚开始使用它在我的项目中。它没有复杂性的限制 :-),您可以自由选择分隔符。我把整个东西放在http://www.jdeer.org下。玩得开心。
如果您想要这种灵活性,但仍然在JVM中运行,那么您可能会选择Groovy。tchrist喜欢忽略Java是强类型语言,而不是像Perl或PHP这样的动态类型语言-并且也喜欢忽略Java运行速度比它们快一个数量级,但显然这只是我“党派”的看法。
->
符号)比缩写版本更易于阅读和维护,但我知道这种观点并不被广泛共享。 - DVK