股票代码的更好的 hashCode 函数?
Better hashCode function for stock ticker symbols?
我将库存对象保存在 HashMap
中,其中键是股票代码 String
(例如 "AAPL"
代表 Apple, Inc.)。不幸的是,这是不可行的,因为 Ally Financial Inc (GM1) 和 Global Partners LP (GLP) 具有冲突的哈希码并且会相互覆盖。例如:"GM1".hashCode() == "GLP".hashCode()
== 主要问题。
是否有 hashCode
可以保证不冲突的股票代码字符串?
public Class StockTicker {
public String symbol;
public StockTicker(String symbol) { this.symbol = symbol; }
@Override
public int hashCode() {
// What goes here?
}
}
成功的答案可能会利用以下事实:股票代码字符串将不超过 5 个字符,并且将是除“.”之外的大写字母数字。如 "BRK.B".
我认为键字符串的 hashCode 对地图本身没有任何影响(我假设您使用的是键的实际股票代码字符串,而不是哈希码;如果您插入到地图中使用哈希码,那么是的,这会导致问题)。我 运行 进行了快速测试,运行良好。
private Map<String, String> stockMap = new HashMap<String, String>();
@Test
public void mapTest() {
stockMap.put("GM1", "gm1stock");
stockMap.put("GLP", "glpstock");
assertEquals(2, stockMap.size());
}
正如 Mshnik 所说,Java 会为您处理碰撞,因此您无需担心。您能否详细说明具体是什么代码导致了您的问题?
正如其他答案和评论所指出的那样,A) Java 将正确处理冲突,前提是您已经以令人满意的方式编写了 equals 和 hashcode,并且 B) 即使获得完美的 hashcode 函数也不能保证这样你就不会发生碰撞。
话虽如此,可以为您的规范编写完美的哈希码函数。您需要担心的字符正好有 37 个(26 个字母、10 个数字和 .
),少于 64 个。因此我们可以使用 6 位来表示每个字符。您最多有 5
个字符,这意味着您的哈希码最多需要 30 位,适合一个 int。
这是创建完美哈希码的实现:
public static class Stock{
// The possible characters of a stock - note length is < 64
private final static String alphaNumeric = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890.";
//Will be 6 for given valid chars, but coding it like this prevents bugs later
private final static int shiftAmnt = (int)(Math.log(alphaNumeric.length()) / Math.log(2)) + 1;
private String stock;
public Stock(String s) {
stock = s;
}
@Override
public boolean equals(Object o) {
return o instanceof Stock && stock.equals( ((Stock)o).stock);
}
@Override
public int hashCode() {
int code = 0;
for (char c : stock.toCharArray()) {
code = code << shiftAmnt;
code += alphaNumeric.indexOf(c);
}
return code;
}
}
我将库存对象保存在 HashMap
中,其中键是股票代码 String
(例如 "AAPL"
代表 Apple, Inc.)。不幸的是,这是不可行的,因为 Ally Financial Inc (GM1) 和 Global Partners LP (GLP) 具有冲突的哈希码并且会相互覆盖。例如:"GM1".hashCode() == "GLP".hashCode()
== 主要问题。
是否有 hashCode
可以保证不冲突的股票代码字符串?
public Class StockTicker {
public String symbol;
public StockTicker(String symbol) { this.symbol = symbol; }
@Override
public int hashCode() {
// What goes here?
}
}
成功的答案可能会利用以下事实:股票代码字符串将不超过 5 个字符,并且将是除“.”之外的大写字母数字。如 "BRK.B".
我认为键字符串的 hashCode 对地图本身没有任何影响(我假设您使用的是键的实际股票代码字符串,而不是哈希码;如果您插入到地图中使用哈希码,那么是的,这会导致问题)。我 运行 进行了快速测试,运行良好。
private Map<String, String> stockMap = new HashMap<String, String>();
@Test
public void mapTest() {
stockMap.put("GM1", "gm1stock");
stockMap.put("GLP", "glpstock");
assertEquals(2, stockMap.size());
}
正如 Mshnik 所说,Java 会为您处理碰撞,因此您无需担心。您能否详细说明具体是什么代码导致了您的问题?
正如其他答案和评论所指出的那样,A) Java 将正确处理冲突,前提是您已经以令人满意的方式编写了 equals 和 hashcode,并且 B) 即使获得完美的 hashcode 函数也不能保证这样你就不会发生碰撞。
话虽如此,可以为您的规范编写完美的哈希码函数。您需要担心的字符正好有 37 个(26 个字母、10 个数字和 .
),少于 64 个。因此我们可以使用 6 位来表示每个字符。您最多有 5
个字符,这意味着您的哈希码最多需要 30 位,适合一个 int。
这是创建完美哈希码的实现:
public static class Stock{
// The possible characters of a stock - note length is < 64
private final static String alphaNumeric = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890.";
//Will be 6 for given valid chars, but coding it like this prevents bugs later
private final static int shiftAmnt = (int)(Math.log(alphaNumeric.length()) / Math.log(2)) + 1;
private String stock;
public Stock(String s) {
stock = s;
}
@Override
public boolean equals(Object o) {
return o instanceof Stock && stock.equals( ((Stock)o).stock);
}
@Override
public int hashCode() {
int code = 0;
for (char c : stock.toCharArray()) {
code = code << shiftAmnt;
code += alphaNumeric.indexOf(c);
}
return code;
}
}