[英]Processing.js HashMap
我在 Processing.js 中迭代 HashMap 时遇到问题。 调用迭代器时,永远不会输入 while(it.hasNext()) 。
作为完整性检查,我尝试跳过迭代器,而是将键转换为数组并按索引迭代这些键。 那也没有用。 我打印了以下内容:
myHashMap.size(); // outputs 4
myHashMap.keySet().size(); // outputs 4
myHashMap.keySet().toArray().length; // outputs 0
我希望最后一行也输出 4,就像他们之前的调用一样。 我理解错了吗? 谢谢!
编辑
这是我遇到的问题的完整示例。 原来是在我的 HashCode 中使用浮点数的问题,尽管我仍然不明白为什么在将 keySet 转换为数组时会导致元素不匹配。
class Vertex {
float x;
float y;
public Vertex(float x, float y) {
this.x = x;
this.y = y;
}
public int hashCode() {
int hash = 17;
hash = ((hash + x) << 5) - (hash + x);
hash = ((hash + y) << 5) - (hash + y);
return hash
}
public boolean equals(Object obj) {
Vertex other = (Vertex) obj;
return (x == obj.x && y == obj.y);
}
}
HashMap<Vertex, String> tmp = new HashMap<Vertex, String>();
Vertex a = new Vertex(1.1, 2.2);
Vertex b = new Vertex(1, 1);
tmp.put(a, "A");
tmp.put(b, "B");
println("1, " + tmp.size()); // outputs 2
println("2, " + tmp.keySet().size()); // outputs 2
println("3, " + tmp.keySet().toArray().length); // outputs 1
我想我终于想通了。 这让我有些头疼。 好问题。
故事寓意:我认为您在使用hashCode()
函数时遇到了一些奇怪的问题。 hashCode()
函数必须返回一个int
值,但您返回的是一个float
值。
要解决您的问题,只需在返回之前将hash
值转换为int
!
public int hashCode() {
int hash = 17;
hash = ((hash + x) << 5) - (hash + x);
hash = ((hash + y) << 5) - (hash + y);
return (int)hash;
}
这可能看起来很奇怪和不必要,所以这里有一个更长的解释:
请注意, x
和y
是float
值,因此当您在hash
计算中使用它们时,结果也会变成float
。 您可以通过在返回之前打印出hash
值来证明这一点。
Java会抱怨这个。 您可以通过简单地切换到 Java 模式并尝试运行您的程序来证明这一点。 但是 JavaScript 对其类型并没有那么严格,因此它可以让您自己动手。 我通常做的事情是在 Java 模式下编程以进行错误检查,然后使用 JavaScript 模式进行部署。
无论如何,在HashMap
类内部, hashCode()
函数的结果最终用作数组中的索引。 您可以在Processing.js源文件中自行查看:
//this is in the HashMap class
function getBucketIndex(key) {
var index = virtHashCode(key) % buckets.length;
return index < 0 ? buckets.length + index : index;
}
function virtHashCode(obj) {
if (obj.hashCode instanceof Function) {
return obj.hashCode();
}
//other code omitted to keep this short
}
这可能没问题,因为奇怪的是 JavaScript 可以在数组索引中使用小数位。 但问题是HashSet's
Iterator
的实现:
function Iterator(conversion, removeItem) {
var bucketIndex = 0;
var itemIndex = -1;
var endOfBuckets = false;
var currentItem;
function findNext() {
while (!endOfBuckets) {
++itemIndex;
if (bucketIndex >= buckets.length) {
endOfBuckets = true;
} else if (buckets[bucketIndex] === undef || itemIndex >= buckets[bucketIndex].length) {
itemIndex = -1;
++bucketIndex;
} else {
return;
}
}
}
//more code
查看findNext()
函数。 它循环遍历数组的索引,但每次递增 1。 因此,任何放入小数位索引的键都将被跳过!
这就是为什么您的迭代器会跳过您的对象之一(从hashCode()
返回的值中带有小数位的对象)。 这就是toArray()
失败的原因,因为该函数在Iterator
使用了Iterator
。
我不会真正将其称为错误,因为问题是由从一个表示将返回int
的函数返回一个float
引起的。 JavaScript 并不像 Java 那样真正需要hashCode()
函数,因此HashMap
和Iterator
这种实现非常合理。 您只需要确保从hashCode()
函数返回一个int
。
顺便说一句,如果您想玩玩,这里有一个较小的示例:
class Thing {
int myThing;
public Thing(int myThing) {
this.myThing = myThing;
}
public int hashCode(){
return myThing;
}
public boolean equals(Object obj) {
Thing other = (Thing) obj;
return (myThing == other.myThing);
}
}
void setup() {
HashMap<Thing, String> map = new HashMap<Thing, String>();
map.put(new Thing(1), "A");
map.put(new Thing(2.5), "B"); //uh oh!
map.put(new Thing(3), "C");
println("1, " + map.size()); // outputs 3
println("2, " + map.keySet().size()); // outputs 3
println("3, " + map.keySet().toArray().length); // outputs 2
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.