2013-04-25 35 views
0

对于作业分配,我必须创建一个程序,将欺骗hang子手。为了做到这一点,我需要想出一种通过字母位置将单词分组到家庭的方法。因此,举例来说,如果单词长度是4,并且他们猜测“e”,那么所有会出现“ - - - e”的单词都会出现在hashmap的Arraylist中,其中一个模式作为关键字, - “将会在另一个相同的hashmap的ArrayLists中以模式作为关键字。我的问题是,尽管我的程序能够识别模式。它仍然返回一个空集或一个包含所有单词的ArrayList。现在我一直在尝试不同的事情一个多小时,我似乎无法让他们正确分组。任何帮助是极大的赞赏。这里是我为类分离单词并将其添加到Hashmap的代码。Java Hashmaps单词分组不会返回多个ArrayList

import java.util.ArrayList; 
import java.lang.StringBuilder; 
import java.util.HashMap; 

public class EvilEngine 
{ 
HashMap<StringBuilder, ArrayList> families = new HashMap<StringBuilder, ArrayList>(); 
int k = 0; 
ArrayList<String> currentList = new ArrayList(); 
StringBuilder blankPattern = new StringBuilder(""); 
StringBuilder newPattern = new StringBuilder(""); 


public void PatternMatcher(ArrayList wordlist, char guess, Integer wordlength) 
{ 

    String word; 
    int j = 0; 
    int x = 0; 
    int biggest = 0; 
    StringBuilder longest = null;  

    while(x < wordlist.size()) 
    { 
     int i = 0; 
     int index = 0; 
     for (i=0; i < wordlength; i++) 
     { 
      blankPattern = blankPattern.append("-"); 
     } 
     boolean boo = false; 
     newPattern = blankPattern; 
     word = (String) wordlist.get(x); 
     index = word.indexOf(guess); 
     while (index >= 0) 
     { 
      blankPattern.setCharAt(index, guess); 
      newPattern = blankPattern; 
      index = word.indexOf(guess, index + 1); 
     } 
     this.PatternCompiler(word,newPattern); 
     blankPattern = blankPattern.delete(0,wordlength); 
     x++; 
    } 
} 
public void PatternCompiler (String word, StringBuilder pattern) 
{ 
     if(!families.containsKey(pattern)) 
     { 
      ArrayList<String> newPatternList = new ArrayList(); 
      newPatternList.add(word); 
      families.put(pattern, newPatternList); 
     } 
     if (families.containsKey(pattern)) 
     { 
      ArrayList<String> oldPatternList = new ArrayList(); 
      oldPatternList = families.get(pattern); 
      oldPatternList.add(word); 
      families.put(pattern, oldPatternList); 
     } 
     else { 
      System.out.println("Error"); 
     } 

} 
public HashMap<StringBuilder, ArrayList> returnFamilies(){ 
    return families; 
} 
} 
+0

“wordlist”中的每个单词是否保证长度为“wordlength”?你应该跳过长度不正确的单词。 – 2013-04-25 01:51:23

+0

是的,我已经将字典文件剪切成只包含适当长度单词的ArrayList。出于某种原因,它不断返回一张空白的地图。 – 2013-04-25 02:00:58

回答

0

虽然有与您的代码几个或多或少的小问题,我怀疑的主要问题是,你的HashMapStringBuilder,而不是String类型的钥匙。 HashMap使用键对象的hashCode()函数来确定它是否已经在地图中。对于StringBuilder,散列值可能只是该对象的地址(使用从Object类继承的实现)。

由于newPattern是一个类级变量,其范围是的功能外,当你把它传递给PatternCompiler()功能,参数pattern存在的仅仅是参考相同类级对象(即,将具有相同的散列码)。并且此对象(或其哈希代码)在您的代码中永远不会更改,因为blankPattern也在类级别声明,并且在更改的值blankPattern时,绝不会更改它引用的对象。因此,每次通过while循环将其重新分配给newPattern不会改变任何内容(并且基本上是混乱的)。

要解决该问题,您需要将HashMap的密钥类型设置为String而不是StringBuilderString类定义了一个hashCode()函数,该函数将根据字符串的实际内容(而不仅仅是像StringBuilder之类的对象的地址)返回不同的代码。 (同时,随着指出,没有理由为blankPattern在类的层次上,而不是只有PatternMatcher()函数内部声明,并且你不需要newPattern在所有。)

虽然这是与主要问题您代码,另一个相当大的问题与PatternCompiler()函数中的第二个if条件有关。在之前的if块中,如果模式中没有一个,则向系列添加新的ArrayList。所以无论如何,第二个if有条件(if (families.containsKey(pattern)))将在这一点上是真实的。因为这两个块将word添加到families的列表中,所以有可能会将一些单词添加两次。

祝你好运!

+0

'StringBuilder'未被记录为实现'hashCode',因此它将使用'Object'的默认实现。*但请不要称之为“对象的地址”,因为这是误导性的,通常甚至是错误的。另外,我还会补充说,使用可变对象作为“Map”的关键字是一种固有的危险操作(偏好'String'的另一个原因)。 – 2013-04-25 06:29:49

+0

@Joachim_Saur关于可变键的好处。我想我的“可能”w.r.t.t.上面的地址太强大了。由于从来没有真正看过它是如何实现的,所以我对“典型”这个词感到好奇,因为它在上面链接到的Object的hashCode()文档的最后一段落中,相对于“通常是错误的”。这是什么正常执行? (并非试图发起争议 - 我真的很好奇。) – Turix 2013-04-25 08:30:34

+0

AFAIK OpenJDK(和Sun JDK)计算一些初始地址的散列并将其存储在对象头中。源代码中有其他实现(包括使用随机函数的实现),但是它们通过编译时开关禁用。不是单独地址的一个主要原因是当垃圾收集器移动对象时,地址可以很容易地改变。 – 2013-04-25 09:34:55