将新密钥放入HashMap会替换现有的不同密钥

时间:2015-10-20 15:11:51

标签: java hashmap

答案: 感谢您的帮助!像大多数人一样,解决方案是创建一个新的2d int数组,并复制旧数组中的值。这是我做的功能,然后我可以将新板添加到hashmap中,作为新密钥。

 void newboard(){
    NewBoard = new int[N][N];
    for(int n = 0; n < N; n++){
        for(int i = 0; i < N; i++){
            NewBoard[n][i] = CurrentBoard[n][i];
        }
    }
}

问题:

我有以下代码,它将一个3x3板和一个整数列表,特别是(f,g,h)放入一个hashmap。理事会CurrentBoard是一个未解决的8难题。

public static HashMap<int[][], List<Integer>> map = new HashMap<>();
map.put(CurrentBoard, fgh);

我初始化了hashmap,对于程序的其余部分,我想迭代遍历地图,以获得我需要的板。地图的每个条目都将是&#39; 0&#39;之后的8-puzzle board的特定状态。位置已被移动。

这是我这样做的方式。 &#39; cv&#39;变量只是选择最低的&#34; f&#34;值。

for(Map.Entry<int[][], List<Integer>> mapentry : map.entrySet()) {
        if (cv > mapentry.getValue().get(0)) {
            cv = mapentry.getValue().get(0);
            CurrentBoard = mapentry.getKey();
            fgh = mapentry.getValue();
        }
}

现在,我已经在&#34; CurrentBoard&#34;变量,我想移动&#39; 0&#39;一排。所以我称之为这个功能:

void moveUp(){
    NewBoard = CurrentBoard;
    memory = NewBoard[ZeroPositionX][ZeroPositionY - 1];
    NewBoard[ZeroPositionY- 1][ZeroPositionX] = 0;
    NewBoard[ZeroPositionY][ZeroPositionX] = memory;
}

然后我做了一些(对于这个问题)不重要的检查,并重新计算此fgh的{​​{1}}值。

然后,我继续使用

NewBoardNewBoard值一起放入fgh
hashmap

我的问题是,它取代了hashmap中的当前键。换句话说,它不是向hashmap添加键和值,而是替换已存在的键和值。我尝试过打印新电路板和当前电路板,以确保它们不同。

当我打印map.put(NewBoard, fgh); 的{​​{1}}时,它只会给我最新的条目。换句话说,董事会以及移动&{39; entrySet()后的价值。

hashmap

为什么将新密钥和值添加到0不起作用?

尾注:我是Java新手,因此其中一些可能不是最佳的。如有必要,我会尽力详细解释。

4 个答案:

答案 0 :(得分:0)

您正在更改NewBoard变量/数组的内容,但引用保持不变。因此,当您调用map.put(NewBoard, fgh);时,密钥始终是相同的引用(在内存中考虑相同的地址,尽管每次都有不同的内容)。

如果要在地图中为每个电路板状态存储新条目,则每次都必须创建一个新数组并复制+更改其内容。

答案 1 :(得分:0)

问题是您正在修改您的HashMap密钥的 function init1() { $('.makeMeDraggable').each(function(i) { $(this).draggable({ revert: true, delay: 100, helper: "clone", appendTo: 'body', //<-==This is what fixed it. containment: "document"}); })} ,而不是创建一个新密钥。这是您的代码摘要(某些行被剪切):

int[][]

请注意,一般来说,修改地图中任意关键字的内容并不是一个好主意 - 它可能导致甚至比您所看到的更奇怪的行为。

另请注意,使用数组作为映射键通常是错误的 - 因为映射依赖于key1.equals(key2)的结果,并且对于任何Java数组CurrentBoard = mapEntry.getKey(); //here CurrentBoard points at the exact same object as the key in your map NewBoard = CurrentBoard; //now NewBoard and CurrentBoard are both pointing at the same int[][] NewBoard[a][b] = 0; //this updates that one object NewBoard[c][d] = memory; //still updating the same object map.put(NewBoard, fgh); //NewBoard is still the same object, so this is replacing the existing key a1, a2仅限于a1.equals(a2)(也就是说,它们是同一个数组)。例如:

a1 == a2

答案 2 :(得分:0)

问题是您正在修改相同的密钥,这将无法按预期工作。要获得“正确”的行为,您应该克隆密钥。由于您的密钥为int[][],因此您无需执行任何操作,只需拨打clone()

    int[][] currentBoard = {{1, 2, 3}, {4, 5, 6}};

    HashMap<int[][], String> map = new HashMap<int[][], String>();

    map.put(currentBoard, "test1");

    int[][] cloned = currentBoard.clone();

    cloned[0][0] = 10;

    map.put(cloned, "test2");

    for(Map.Entry mapentry : map.entrySet()){
        System.out.println(mapentry.getValue());
    }

打印

test1
test2

如果您想使用自己创建的某个课程,则需要覆盖clone(),请参阅Cloneable

重要的是要注意clone()只会克隆数组引用,而不是它的值。所以currentBoard[0].equals(cloned[0])将是真的,但我认为这对你的案例没有任何影响。

另见关于克隆Java: recommended solution for deep cloning/copying an instance

的问题

答案 3 :(得分:0)

更改int[][]类型的地图关键字中的值不会改变其equalshashCode方法的行为方式。这些是被调用以确定密钥在语义上是否相同的方法。

因此,要添加新密钥,您必须创建一个新密钥或使用具有不同equals / hashCode逻辑的正确类。

要创建新密钥,您可以使用clone()

void moveUp() {
    NewBoard = new int[3][3];
    NewBoard[0] = CurrentBoard[0].clone();
    NewBoard[1] = CurrentBoard[1].clone();
    NewBoard[2] = CurrentBoard[1].clone();
    memory = NewBoard[ZeroPositionX][ZeroPositionY - 1];
    NewBoard[ZeroPositionY- 1][ZeroPositionX] = 0;
    NewBoard[ZeroPositionY][ZeroPositionX] = memory;
}

注意,我们必须调用clone三次,因为它无法完全克隆双暗阵列(请参阅here)。

更简洁的方法是创建一个这样的Board类(未经测试,请原谅错别字):

public class Board {

    private int[][] content = new int[3][3];

    /**
     * Creates a new empty board.
     */
    public Board() {
    }

    /**
     * Call this constructor to create a new instance of a given board.
     */
    public Board(Board otherBoard) {
        this.content[0] = otherBoard.content[0].clone()
        this.content[1] = otherBoard.content[1].clone()
        this.content[2] = otherBoard.content[2].clone()
    }

    public void set(int a, int b, int value) {
        content[a][b] = value;
    }

    public int get(int a, int b) {
        return content[a][b];
    }

    public int hashCode() {
        int code = 0;
        for (int a=0; a<3; a++) {
            for (int b=0; b<3; b++) {
                code += content[a][b];
            }
        }
        return code;
    }  

    public boolean equals(Object that) {
        if (!(that instanceof Board)) return false;
        return Arrays.equals(this.content[0], that.content[0])
            && Arrays.equals(this.content[1], that.content[1])
            && Arrays.equals(this.content[2], that.content[2])
    }
}

总的来说,您应该在https://docs.oracle.com/javase/8/docs/api/java/util/Map.html

中研究Map的一般合同

此外,在您的代码中,确保在<{1}}中使用密钥后,永远不会更改密钥的内容。否则混乱就会统治......

祝你好运。