繁体   English   中英

Processing.js HashMap

[英]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;
  }

这可能看起来很奇怪和不必要,所以这里有一个更长的解释:

请注意, 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'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()函数,因此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
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM