当映射明确包含它们时,HashMap键将返回null [英] HashMap keys return null when the map demonstrably contains them

查看:99
本文介绍了当映射明确包含它们时,HashMap键将返回null的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正试图解决标题为战舰:沉没受损或未触及的代码大战问题。给定一个包含'船'的二维数组和包含攻击坐标的另一个二维数组,我必须生成一个分数。我使用船舶位置填充散列表,然后根据地图检查攻击位置。打印时,第一个测试用例的原始位置和攻击是相同的。尽管如此, map.get()继续返回 null map.containsKey()返回 false

  public class BattleshipsSDN {
public static Map< String,Double> ; damagedOrSunk(final int [] [] board,final int [] []攻击){

int y;
HashMap< int [],Integer>船=新的HashMap<>();

//建立船位置图
(int i = 0; i< board.length; i ++){
y = board.length - i;
for(int j = 0; j< board [i] .length; j ++){
if(board [i] [j] == 0)
else {
int [] location = {j + 1,y};
ships.put(location,board [i] [j]);
System.out.println(Location:+ location [0] +,+ location [1]);
//System.out.println(\"Value:+ ships.get(location));




//建立原始船长
int ship1 = Collections.frequency(new ArrayList< Integer>(ships.values( )),1);
int ship2 = Collections.frequency(new ArrayList< Integer>(ships.values()),2);
int ship3 = Collections.frequency(new ArrayList< Integer>(ships.values()),3);
System.out.println(船舶:+ ship1 + ship2 + ship3); (int [] x:ships.keySet())

System.out.println(x [0] +,+ x [1]);

//检查点击
(int [] x:attacks){
System.out.println(x [0] +,+ x [1] );
if(ships.get(x)== null)继续;
else {
System.out.println(Hit);
ships.remove(x);
}
}

double sunk = 0;
double hit = 0;
double missed = 0;

//找到发生攻击后的船点数目
int leftShip1 = Collections.frequency(new ArrayList< Integer>(ships.values()),1);
int leftShip2 = Collections.frequency(new ArrayList< Integer>(ships.values()),2);
int leftShip3 = Collections.frequency(new ArrayList< Integer>(ships.values()),3);
System.out.println(船舶:+ leftShip1);

if(ship1> 0){
if(leftShip1 == 0)sunk ++;
else if(ship1%leftShip1> 0)hit ++;
else if(ship1 == leftShip1)missed ++;
}
if(ship2> 0){
if(leftShip2 == 0)sunk ++;
else if(ship2%leftShip2> 0)hit ++;
else if(ship2 == leftShip2)missed ++;
}
if(ship3> 0){
if(leftShip3 == 0)sunk ++;
else if(ship3%leftShip3> 0)hit ++;
else if(ship3 == leftShip3)missed ++;
}
HashMap< String,Double> score = new HashMap<>();
score.put(沉没,沉没);
score.put(损坏,点击);
score.put(notTouched,错过);
score.put(points,沉没+击中/ 2 - 错过);
的回报分数;






$ b

我不是要你为我解决问题。我完全被难住为什么我的HashMap是这样行事的。这可能意味着这是一些非常愚蠢的事情。



注意:位置的 y 值会翻转,因为在问题'board'中,y-coord从底部开始测量。因此,在4x4板或阵列中,索引[0] [0]对应于坐标(1,4)。解释方案

解释方案

解释



问题在于你使用 int [] 作为你的 HashMap 。数组不会覆盖方法 equals hashCode 。因此,对于他们来说,这些方法是通过身份而不是内容来比较对象的。 / p>

  int [] first = new int [] {1,2,3}; 
int [] second = new int [] {1,2,3};

System.out.println(first.equals(second)); //打印'false'

两个数组都有相同的内容被认为是不等于,因为它们是不同的对象( first!= second )。

当您现在调用类似 map.get(key)时,地图通过使用散列码搜索关键 strong>,它是由 hashCode 方法返回的。但是,此方法也适用于数组的身份基础



如果您现在使用键存储数据,并且稍后重新创建关键字与相同的内容,为了获取数据,你不会再找到它:

  Map< int [],串GT; map = new HashMap<>(); 

//放入数据
int [] key = new int [] {1,2,3};
map.put(key,test);

//检索它
int [] similarKey = new int [] {1,2,3};
String data = map.get(similarKey); //是'null',而不是'test'

//用'key'而不是'similarKey'试试它
String otherData = map.get(key); //现在工作,因为同一对象

虽然 similarKey 具有相同的内容,它具有不同的 hashCode ,因为它是不是同一个对象(通过身份)。






解决方案



要解决这个问题,只需使用一个数据结构来实现 hashCode 等于不是每个身份,而是每个比较内容。您可以使用集合 documentation ), ArrayList

 <$ c $ / doc / api / java / util / ArrayList.htmlrel =nofollow noreferrer> documentation ) c> Map< List< Integer> ;, String> map = new HashMap<>(); 

//放入数据
int [] key = new int [] {1,2,3};
列表<整数> keyAsList = new ArrayList<>(Arrays.asList(key));
map.put(keyAsList,test);

//检索它
int [] similarKey = new int [] {1,2,3};
列表<整数> similarKeyAsList = new ArrayList<>(Arrays.asList(similarKey));
String data = map.get(similarKeyAsList); //现在'测试'


I'm currently trying to solve a code wars problem titled Battle ships: Sunk damaged or not touched?. Given a 2D array containing 'ships' and another 2D array containing the attack coordinates I have to generate a score. I populate a hashmap with the ship locations and then check the attack locations against the map. When printed, the original locations and attacks are identical on the first test case. Despite this, map.get() continues to return null and map.containsKey() returns false.

public class BattleshipsSDN {
public static Map<String,Double> damagedOrSunk(final int[][] board, final int[][] attacks) {

    int y;
    HashMap<int[], Integer> ships = new HashMap<>();

    // build map of boat locations
    for (int i = 0; i < board.length; i++) {
        y = board.length - i;
        for (int j = 0; j < board[i].length; j++) {
            if (board[i][j] == 0) continue;
            else {
                int[] location = {j+1,y};
                ships.put(location, board[i][j]);
                System.out.println("Location: "+location[0]+","+location[1]);
                //System.out.println("Value: "+ships.get(location));
            }
        }
    }

    //establish original boat lengths
    int ship1 = Collections.frequency(new ArrayList<Integer>(ships.values()), 1);
    int ship2 = Collections.frequency(new ArrayList<Integer>(ships.values()), 2);
    int ship3 = Collections.frequency(new ArrayList<Integer>(ships.values()), 3);
    System.out.println("Ships: "+ship1+ship2+ship3);

    for(int[] x : ships.keySet()) System.out.println(x[0]+","+x[1]);

    //check for hits
    for (int[] x : attacks) {
        System.out.println(x[0]+","+x[1]);
        if (ships.get(x) == null) continue;
        else{
            System.out.println("Hit");
            ships.remove(x);
        }
    }

    double sunk = 0;
    double hit = 0;
    double missed = 0;

    //find number of ship spots after attacks
    int leftShip1 = Collections.frequency(new ArrayList<Integer>(ships.values()), 1);
    int leftShip2 = Collections.frequency(new ArrayList<Integer>(ships.values()), 2);
    int leftShip3 = Collections.frequency(new ArrayList<Integer>(ships.values()), 3);
    System.out.println("Ships: "+leftShip1);

    if (ship1 > 0) {
        if (leftShip1 == 0) sunk++;
        else if (ship1 % leftShip1 > 0) hit++;
        else if (ship1 == leftShip1) missed++;
    }
    if (ship2 > 0) {
        if (leftShip2 == 0) sunk++;
        else if (ship2 % leftShip2 > 0) hit++;
        else if (ship2 == leftShip2) missed++;
    }
    if (ship3 > 0) {
        if (leftShip3 == 0) sunk++;
        else if (ship3 % leftShip3 > 0) hit ++;
        else if (ship3 == leftShip3) missed++;
    }
    HashMap<String, Double> score = new HashMap<>();
    score.put("sunk", sunk);
    score.put("damaged", hit);
    score.put("notTouched", missed);
    score.put("points", sunk + hit/2 - missed);
    return score;

}

}

I'm not asking you to solve the problem for me. I'm just completely stumped as to why my HashMap is acting this way. Which likely means it's some really small stupid thing.

Note: The y values of the locations are flipped because in the problems 'board' the y-coord is measured from the bottom. So in a 4x4 board or array the index [0][0] corresponds to the coordinates (1,4)

解决方案

Explanation

The problem is that you are using int[] as key for your HashMap. Arrays don't override the methods equals and hashCode. Thus those methods, for them, compares objects by their identity instead of their content.

Consider this:

int[] first = new int[] { 1, 2, 3 };
int[] second = new int[] { 1, 2, 3 };

System.out.println(first.equals(second)); // Prints 'false'

Both arrays have the same content but they are considered not equal since they are different objects (first != second).

When you now call something like map.get(key) the map searches for the key by using its hash-code, the one returned by the hashCode method. However this method also works on an identity-base for arrays.

If you now store the data with a key and later re-create a key with the same content, in order to fetch the data, you will not find it anymore:

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

// Put data
int[] key = new int[] { 1, 2, 3 };
map.put(key, "test");

// Retrieve it
int[] similarKey = new int[] { 1, 2, 3 };
String data = map.get(similarKey); // Is 'null', not ' test'

// Try it with 'key' instead of 'similarKey'
String otherData = map.get(key); // Works now since same object

Though similarKey has the same content, it has a different hashCode since it is not the same object (by identity).


Solution

To solve the issue simply use a data-structure which implements hashCode and equals not per identity but per comparing the content. You may use stuff from Collection (documentation), an ArrayList (documentation) for example:

Map<List<Integer>, String> map = new HashMap<>();

// Put data
int[] key = new int[] { 1, 2, 3 };
List<Integer> keyAsList = new ArrayList<>(Arrays.asList(key));
map.put(keyAsList, "test");

// Retrieve it
int[] similarKey = new int[] { 1, 2, 3 };
List<Integer> similarKeyAsList = new ArrayList<>(Arrays.asList(similarKey));
String data = map.get(similarKeyAsList); // Is 'test' now

这篇关于当映射明确包含它们时,HashMap键将返回null的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆