【问题标题】:Reading .txt File into a Hashmap and manipulating it将 .txt 文件读入 Hashmap 并对其进行操作
【发布时间】:2017-03-26 22:43:19
【问题描述】:

尽管查看了一些教程,但我最大的问题很可能是没有完全理解 Hashmap 以及如何操作它们。希望你们聪明的灵魂能够为我指明正确的方向。

我正在尝试将 .txt 文件读入哈希图中。文本文件包含 2006 年的流行名称。 inputFile 的每一行都包含一个男孩的名字和一个女孩的名字以及有多少人被命名。例如:1 Jacob 24,797 Emily 21,365 将是文件第 1 行的输入。

我想把男孩的名字放在一个列表中,女孩的名字放在第二个列表中,保持他们当前的位置,这样用户就可以搜索 jacob 并被告知这是当年排名第一的男孩名字,依此类推对于其他名称。以前我只是逐行读取文件并查看文件包含我正在搜索的名称的哪一行。这有效,但它无法判断它是男孩名字还是女孩名字,导致错误,如果我说我正在搜索 Jacob 对女孩的受欢迎程度,它仍然会显示数字 1。我确定 hashmap 会成为解决此问题的最佳方法,但无法真正使其正常工作。

我的代码

public void actionPerformed(ActionEvent e)
    {
        //Parse Input Fields
        String name = inputArea.getText();
        if (name.equals(""))
        {
            JOptionPane.showMessageDialog(null, "A name is required.", "Alert", JOptionPane.WARNING_MESSAGE );
            return;
        }
        String genderSelected = genderList.getSelectedItem().toString();
        String yearSelected = yearList.getSelectedItem().toString();

        String yearFile = "Babynamesranking"+yearSelected+".txt";    //Opens a different name file depending on year selection    
        boolean foundName = false;
        Map<String, String> map = new HashMap<String,String>(); //Creates Hashmap

        try
        {
            File inputFile = new File(yearFile);                    //Sets input file to whichever file chosen in GUI
            FileReader fileReader = new FileReader(inputFile);      //Creates a fileReader to open the inputFile
            BufferedReader br = new BufferedReader(fileReader);     //Creates a buffered reader to read the fileReader

            String line;
            int lineNum = 1;                                        //Incremental Variable to determine which line the name is found on
            while ((line = br.readLine()) != null)
            {
                if (line.contains(name))
                {
                    outputArea.setText(""+name+" was a popular name during "+yearSelected+".");
                    outputArea.append("\nIt is the "+lineNum+" most popular choice for "+genderSelected+" names that year.");
                    foundName = true;
                }
                String parts[] = line.split("\t");
                map.put(parts[0],parts[1]);

                lineNum++;
            }
            fileReader.close();
        }
        catch(IOException exception)
        {
            exception.printStackTrace();
        }

        String position = map.get(name);
        System.out.println(position);
}

示例输入文件:

1   Jacob   24,797  Emily   21,365
2   Michael 22,592  Emma    19,092
3   Joshua  22,269  Madison     18,599
4   Ethan   20,485  Isabella    18,200
5   Matthew 20,285  Ava     16,925
6   Daniel  20,017  Abigail     15,615
7   Andrew  19,686  Olivia  15,474
8   Christopher 19,635  Hannah  14,515

【问题讨论】:

  • 总是男孩名后女孩名的情况,还是可以颠倒?
  • 总是这样
  • 如果(男孩被选中)查看部分[0],否则查看部分[1]。
  • 使得 hashmap 包含 {name,popularity} 对。

标签: java file-io hashmap


【解决方案1】:

好吧,问题在于使用

if (line.contains(name))

您正在检查该名称是否存在于整行中,以确定它是男孩的名字还是女孩的名字。您可以做的是分别阅读它们,然后决定要检查的值。你可以这样做:

while ((line = br.readLine()) != null)
{
    Scanner sc = new Scanner(line);
    int lineNumber = sc.nextInt();
    String boyName = sc.next();
    int boyNameFreq = sc.nextInt();
    String girlName = sc.next();
    int girlNameFreq = sc.nextInt();

    if(genderSelected.equals("male") && name.equals(boyName)){
        // .. a boy's name is found
    }
    else if(genderSelected.equals("female") && name.equals(girlName)){
        // .. a girl's name is found
    }

}

Scanner 类用于解析该行,并逐个标记读取它,因此您可以知道该名称是男孩还是女孩。然后检查您只需要的名称。

【讨论】:

  • 而不是两个 if,使用 if{}else if{} 会更有意义。
  • 否,因为每个不满足 if {} 的条件都会执行 else 语句。因此,如果您的名字与男孩名不匹配,即使它也不匹配女孩名,它也会直接执行 else 块,因为您没有在 else 语句中检查该条件。
  • 这看起来可以让我使用哈希图。不过,我最初确实遇到了运行时错误。它编译但在执行时崩溃。必须将 int 更改为双精度数。
  • @Islam Hassan:如果第一个条件已经满足,为什么还要检查第二个条件?这是一种不好的做法。
  • @Justiciar 很奇怪。我试过了,它应该可以很好地处理整数,除非你有非常大的数字(超过 20 亿)。崩溃时的错误信息是什么意思?
【解决方案2】:

您需要两个哈希图,一个用于男孩的名字,一个用于女孩的名字 - 目前您使用男孩的名字作为键,女孩的名字作为值,这不是您想要的。相反,使用两个Map&lt;String, IntTuple&gt; 数据结构,其中String 是名称,IntTuple 是行号(排名)和具有此名称的人数。

class IntTuple {
  final int rank;
  final int count;

  IntTuple(int rank, int count) {
    this.rank = rank;
    this.count = count;
  }
}

【讨论】:

  • 这是有道理的。我对“钥匙”有点困惑。我将在代码中使用它
  • 根据他的代码,不需要创建两个hashmap,因为前端用户已经选择了性别,所以只需要一个hashmap。
  • @Justiciar 键是您用来查找值的键,例如,如果您的哈希映射包含映射到“1, 24,797”IntTuple 值的“Jacob”键,那么“map.get( "Jacob")" 将返回 "1, 24,797" 值
猜你喜欢
  • 2017-03-12
  • 2018-08-09
  • 2012-06-17
  • 1970-01-01
  • 1970-01-01
  • 2017-03-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多