2016-04-07 79 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