2016-04-07 45 views
2

我在Processing.js中有一个遍历HashMap的问题。在调用迭代器时,(it.hasNext())永远不会输入。Processing.js HashMap

作为一个健全性检查,我试图跳过迭代器,而是将键转换为一个数组,并通过索引来遍历这些键。那也行不通。我打印出来的情况如下:

myHashMap.size();   // outputs 4 
myHashMap.keySet().size(); // outputs 4 
myHashMap.keySet().toArray().length; // outputs 0 

我希望最后一行也输出4,因为他们以前的电话一样。我理解错误吗?谢谢!


编辑

这里是我运行到这个问题的一个完整的例子。原来是在我的HashCode中使用float的问题,但我仍然不明白为什么在将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 
+0

请发表[MCVE],显示我们,正是你正在运行的代码。请注意,这应该只是几行,对于我们复制和粘贴以获得相同的结果足够了,但不是您的整个草图! –

+0

这段代码适用于我:'HashMap map = new HashMap (); 012.map.put(“one”,“A”); map.put(“two”,“B”); map.put(“three”,“C”); println(map.size()); println(map.keySet()。toArray()。length);' –

+0

啊,谢谢Kevin!对不完整的例子感到抱歉。你的反应让我从较低的层面进行调试。我的问题原来是我的HashMap中的键是对象,并且我为这些对象创建的hashCode由于错误地使用了float而失败。我仍然不明白为什么调用keySet()。size()和keySet()。toArray()。length会产生不同的值。我会发布一个更新的代码示例,以及我真正遇到的情况,以防有人感兴趣。再次感谢! – megabits

回答

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; 
    } 

这似乎奇怪的和不必要的,所以这里有一个更详细的解释:

注意xyfloat值,所以当你在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'sIterator实现:

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()功能。它循环遍历数组的索引,但每次增加一个。因此,任何放入小数点索引的键都将被跳过!

这就是为什么你的迭代器跳过你的一个对象(从hashCode()返回的值中有一个小数位的对象)。这就是为什么toArray()失败的原因,因为该功能在底层使用Iterator

我不会真的把这称为一个错误,因为问题是由返回float的函数返回int。 JavaScript并不真的需要hashCode()函数与Java相同的方式,所以这个实现HashMapIterator是非常合理的。你只需要确保你从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 
} 
+1

哇,太棒了!这需要一些追踪:)永远不会想到这一点,但基于整数索引递增当然是有道理的。感谢有关在Java模式下开发的建议,绝对要这样做。感谢您解决这个谜团,并且..您知道的越多! – megabits