简体   繁体   English

比较数组值和HashMap

[英]Comparing Array Values and HashMap

I was making a rock paper scissors game and I'm supposed to save the last four throws of the user into a HashMap. 我当时正在制作剪刀石头布的游戏,应该将用户的最后四步保存到HashMap中。 The last four throws will be inside a Pattern class. 最后四次抛出将在Pattern类中。 I have it so that if the pattern is already in the HashMap, then the value will be incremented by one, showing that the user have repeated that pattern one time. 我拥有它,以便如果该模式已经在HashMap中,则该值将增加1,表明用户已重复该模式一次。 The patterns will be used to predict the user next move. 这些模式将用于预测用户的下一步行动。 However, when I compare the two patterns, the one in the HashMap and the one I just passed in, even though they are not the same, it returns that they are the same. 但是,当我比较两种模式时,即使HashMap中的一种和我刚刚传入的一种,即使它们不相同,它也会返回它们是相同的。 I have tried looking into this for a while but I couldn't find out what's wrong. 我已经尝试研究了一段时间,但是我找不到问题所在。 Some help would be greatly appreciated! 一些帮助将不胜感激! The error comes right at the second input. 错误在第二个输入处出现。 If I input R, it will save it in the HashMapbut when I input anything else, it will throw a NullPointerException, which I think because the new pattern is not stored inside the hashmap but I tried to get the value of it since the program thinks that it is equal to the one already inside the HashMap. 如果我输入R,它将保存在HashMap中,但是当我输入其他任何内容时,它将抛出NullPointerException,我认为是因为新模式未存储在哈希图中,但是由于程序认为,我试图获取它的值它等于HashMap内部已经存在的那个。 I think the problem is inside the equals() in Pattern but I'm not entirely sure. 我认为问题出在Pattern的equals()内部,但我不确定。

import java.util.*;

public class RockPaperScisors{
  public static void main(String[] args){
    Scanner key = new Scanner(System.in);
    Pattern pattern = new Pattern();
    Pattern pattern1;
    Computer comp = new Computer();
    boolean stop = false;
    int full=0;;
    while ( !stop ){

      System.out.println("Enter R P S. Enter Q to quit.");
      char a = key.next().charAt(0);
      if ( a == 'Q' ){
        stop = true;
        break;
      }
      pattern.newPattern(a);
      char[] patt = pattern.getPattern();

      for ( int i = 0; i < patt.length; i++ ){
        System.out.print(patt[i] + " ");
      }

      pattern1 = new Pattern(patt);
      comp.storePattern(pattern1);

      System.out.println();
      System.out.println("Patterns: " + comp.getSize());
      full++;
    }
  }
}

import java.util.*;

public class Pattern{
  private char[] pattern;
  private int full = 0;

  public Pattern(){
    pattern = new char[4];
  }

  public Pattern(char[] patt){
    pattern = patt;
  }

  public char[] getPattern(){
    return pattern;
  }

  public void newPattern(char p){
    if ( full <= 3 ){
      pattern[full] = p;
      full ++;
    }
    else{
      for (int i = 0; i <= pattern.length-2; i++) {
        pattern[i] = pattern[i+1];
      }
      pattern[pattern.length-1] = p;
    }
  }

  public int HashCode(){
    char[] a = pattern;
    return a.hashCode();
  }

  public boolean equals( Object o ) {
    if( o == this ) {  return true; }
    if(!(o instanceof Pattern)){ return false; }
    Pattern s = (Pattern) o;
    if (Arrays.equals(s.getPattern(), pattern))
      System.out.println("Yes");
    return Arrays.equals(s.getPattern(), pattern);
  }
}

import java.util.*;
import java.util.Map.Entry;

public class Computer{
  private HashMap<Pattern, Integer> map;

  public Computer(){
    map = new HashMap <Pattern, Integer>();
  }

  public void storePattern(Pattern p){
    boolean contains = false;
    for (Entry<Pattern, Integer> entry : map.entrySet())
    {
      Pattern patt = entry.getKey();
      if ( p.equals(patt) ){
        contains = true;
      }
    }
    if ( contains ){
      int time = map.get(p);
      time++;
      map.put(p, time);
    }
    else
      map.put(p, 0);
  }

  public int getSize(){
    return map.size();
  }
}

Your HashCode is wrong. 您的HashCode错误。

It should be written in lower case. 应该用小写形式。

 public int hashCode()

In order to make sure that the method is overwritten, use the @Override annotation. 为了确保该方法被覆盖,请使用@Override批注。

It's entirely possible that the issue in Pattern#HashCode . Pattern#HashCode中的问题完全有可能。

The first issue is that it's not being used (it should be Pattern#hashCode ), the second is that it's not calculating what you think it is. 第一个问题是它没有被使用(应该是Pattern#hashCode ),第二个问题是它没有计算出您认为的含义。

You may find java.util.Arrays#hashCode very useful, changing the backing from an array to a List would also work. 您可能会发现java.util.Arrays#hashCode非常有用,将数组的支持从数组更改为List也将起作用。

As a side note, Pattern is not a great choice for the name of that class, as it clashes with java.util.regex.Pattern . 附带说明一下, Pattern不是该类名称的理想选择,因为它与java.util.regex.Pattern冲突。 This is more of a problem in this case than it might be otherwise, as it can be used with Scanner . 在这种情况下,与其他情况相比,这更是一个问题,因为它可以与Scanner一起使用。

As noted by another answer, the first thing to do is rename and annotate your hashcode() method. 正如另一个答案所指出的,要做的第一件事是重命名并注释您的hashcode()方法。

And then, you also have to fix it. 然后,您还必须修复它。 It uses 它用

char[] a = pattern;
return a.hashCode();

This means it uses the char[] object's hashCode() function. 这意味着它使用char[]对象的hashCode()函数。 But that function is inherited directly from Object , and gives you a different hash code for two equal character arrays. 但是该函数直接从Object继承,并为两个相等的字符数组提供了不同的哈希码。 For example, try this: 例如,尝试以下操作:

    char[] c = { 'a','b','c' };
    char[] d = { 'a','b','c' };
    System.out.printf("%d %d%n", c.hashCode(), d.hashCode());

And you'll see that it prints two different numbers. 您会看到它打印两个不同的数字。

So you need to use a better hash code function. 因此,您需要使用更好的哈希码功能。 You can make your own, or use Arrays.hashCode(pattern) (there is no need for the local a variable). 您可以自己制作,也可以使用Arrays.hashCode(pattern) (不需要在本地a变量)。 The important thing is that when two Patterns are equal according to the equals() method, they should have the same hash code. 重要的是,当两个模式根据equals()方法equals() ,它们应该具有相同的哈希码。

What happens in your case is that you look up the HashCode by testing equality of all the entry keys (I'll get to that in a minute, it's a bad thing to do), so equals tell you you have the same key in the hash map. 在这种情况下,您会通过测试所有输入键的相等性来查找HashCode(我将在一分钟内完成,这是一件坏事),所以equals告诉您您在输入键中具有相同的键哈希图。 But the hash map itself uses the hashCode() method in get() to locate the object. 但是哈希图本身使用get()hashCode()方法来定位对象。 And according to the hashCode() method, there is no object in the hash map that has the same key! 根据hashCode()方法,哈希图中没有具有相同键的对象!

So they must always agree when the objects are equal. 因此,当对象相等时,它们必须始终保持一致。


Now, as for your method of looking up the object: 现在,至于您查找对象的方法:

boolean contains = false;
for (Entry<Pattern, Integer> entry : map.entrySet())
{
    Pattern patt = entry.getKey();
    if ( p.equals(patt) ){
        contains = true;
    }
}
if ( contains ){
  int time = map.get(p);
  time++;
  map.put(p, time);
} else
  map.put(p, 0);

This is not how you use a Map . 不是您使用Map The whole point of a HashMap is that you can see if it contains a certain key or not in O(1). HashMap的全部要点是,您可以查看它是否在O(1)中包含某个键。 What you are doing is iterating it and comparing - and that`s O(N), very wasteful. 您正在做的是对其进行迭代并进行比较-这是O(N),非常浪费。

If you implement your hashCode() properly, you can just look it up by doing map.containsKey(p) instead of that loop. 如果正确实现hashCode() ,则可以通过执行map.containsKey(p)而不是该循环来查找它。 And if you are certain that you are not putting null values in the map, you can simply use get() to get your pattern: 而且,如果确定没有在映射中放入空值,则可以简单地使用get()来获取模式:

Integer time = map.get(p);

if ( time == null ) {
     map.put( p, 0 );
} else {
     map.put( p, time+1);
}

(You don't need to use ++ , because you are not actually using time after you put it in the map). (您无需使用++ ,因为将其放入地图后实际上并未使用time )。

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

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