【问题标题】:Adding multiple keys to a value in hashMap向 hashMap 中的值添加多个键
【发布时间】:2017-10-11 02:33:51
【问题描述】:

我目前有以下 HTML 格式的数据:

Year| car type     | # of cars sold
2001| Toyota-Camry | 242435
2000| Honda-Accord | 344423
2001| Honda-Accord | 555255
2000| Honda-Civic  | 342344
2008| Toyota-Prius | 666154
1996| Honda-Accord | 114526
2001| Toyota-Prius | 90234

为了检索这些数据,我有一个BufferedReader,它从 HTML 中读取行。在数据出现之前,我在开头跳过了几行,因为有空格。所以我目前的代码是

public class carSales {
    private Map<Integer, HashMap<Integer, String>> carSalesMan = 
            new HashMap <Integer, HashMap<Integer, String>>;

private void getcarTypes(String url) {
    try {
    URL urlz = new URL(url);
    URLConnection urlc = myURL.openConnection();
    BufferedReader line = new BufferedReader
    (new InputStreamReader(urlConnection.getInputStream()));

    String next;
    next = line.readLine(); 

    while (next.contains("</s>") {
        String[] parts = next.split(" ");

        if (carSalesMan.isEmpty() || carSalesMan.get(Integer.parseInt(parts[0])) == null {
            carSalesMan.put(Integer.parseInt(parts[0], new HashMap<Integer, String>());
            carSalesMan.get(Integer.parseInt(parts[0])).put(Integer.parseInt(parts[2]), parts[1])

        }
    }
    catch (IOException e) {
    }
}

问题在于它似乎只存储具有唯一年份的数据。所以我的carSalesMan 变量的大小将是 4,因为我只有 4 个独特的年份,并且随着列表的下降,它们会相互覆盖。有没有一种简单的方法可以添加所有车型,即使是同一年?

【问题讨论】:

  • 是的,Map 是键到值的唯一映射。您可能应该做的是创建一个包含年份、汽车类型和销售单位的对象(不要忘记.equals().hashcode(),然后将它们放入一个结构(可能是一个集合)并根据需要进行处理。
  • 这看起来不像是Map 的用例。随着每次添加新字段,您注定要不断嵌套越来越多的Maps。相反,您应该创建一个Car 类,并使用List&lt;Car&gt;Set&lt;Car&gt;
  • @4castle 是的,我理解,但不幸的是,这是使用 HashMaps 和 Maps 的项目要求
  • 您能否详细说明项目的实际要求,因为这可能是 XY 问题。

标签: java html hashmap synchronization bufferedreader


【解决方案1】:

因为你的 if 语句,所以只有一项:

    if (carSalesMan.isEmpty() || carSalesMan.get(Integer.parseInt(parts[0])) == null {

您有两个选择,如果您想为每个项目设置不同的插槽,您需要选择@JacobG。回答,或者您可以删除此 if 语句并使用将项目集合存储为值的映射类型。您将有两种方法来执行第二个选项:

我相信您想要一个 MultiValueMap 而不是 HashMap,它的工作方式几乎与 HashMap 完全相同,只是它将每个键的值存储在集合中,而不是每个键上只存储一个值。

它不是官方的 Java,但它是开源的。 您可以在此处找到文档:

http://commons.apache.org/proper/commons-collections/apidocs/org/apache/commons/collections4/MultiValuedMap.html

或者,您可以使用自定义类自己实现它,该类扩展 HashMap&lt;K, V&gt; 封装 HashMap&lt;K, Collecton&lt;V&gt;&gt;

【讨论】:

  • 无法弄清楚如何在我的回答中标记@jacob-g
  • 别担心 :)
【解决方案2】:

您在这里尝试实现的是利用两个单独的键来存储一个值。使用 Guava 等外部库,这相当于 Table&lt;Integer, Integer, String&gt;。如果您不想使用任何外部库,那么在这种情况下使用 Map&lt;Integer, Map&lt;Integer, String&gt;&gt; 是一个非常好的对象。

您当前代码的问题在于,它仅在 Map 为空或不包含特定年份时添加信息。您可以将其更改为以下内容,它会正常工作:

public class carSales {
    private Map<Integer, Map<Integer, String>> carSalesMan = new HashMap<>();

    private void getcarTypes(String url) {
        try {
            URL urlz = new URL(url);
            URLConnection urlc = urlz.openConnection();

            BufferedReader line = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));

            String next = line.readLine(); 

            while (next.contains("</s>") {
                String[] parts = next.split(" ");

                int year = Integer.parseInt(parts[0]);
                int amountSold = Integer.parseInt(parts[2]);
                String model = parts[1];

                carSalesMan.putIfAbsent(year, new HashMap<>());
                carSalesMan.get(year).put(amountSold, model);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

记得关闭你的连接/阅读器以防止内存泄漏!

编辑:如果您想使用 Guava 的 Table ADT,您可以使用以下内容:

public class carSales {
    private Table<Integer, Integer, String> carSalesMan = HashBasedTable.create();

    private void getcarTypes(String url) {
        try {
            URL urlz = new URL(url);
            URLConnection urlc = urlz.openConnection();

            BufferedReader line = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));

            String next = line.readLine(); 

            while (next.contains("</s>") {
                String[] parts = next.split(" ");

                int year = Integer.parseInt(parts[0]);
                int amountSold = Integer.parseInt(parts[2]);
                String model = parts[1];

                carSalesMan.put(year, amountSold, model);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

【讨论】:

  • 感谢您的回答!!如果可以,您能否详细说明关闭我的联系和读者?
  • 不客气!当然。我不确定您是否担心如何正确关闭连接/阅读器,或者为什么要关闭它们,所以如果您能指定它会很有帮助。如果您不关闭连接/阅读器,则关联的系统资源将不会释放。不关闭它们是不好的做法,因为持续打开连接会由于所需资源不足而导致内存泄漏。
  • 我想知道你应该如何关闭连接/阅读器。
  • 从技术上讲,我认为URLConnection 不会给您带来任何问题,但您可以在while 循环终止后调用line.close();
  • 这是对所问问题的一个很好的回答,但是我认为这个陈述可能不是真的:“a Map> 是一个非常好的对象,可以用于这个案例”。我怀疑是否真的需要按售出的汽车数量进行地图查找,此外,如果两种型号在给定年份的销量相同,那么数据就会丢失。不幸的是,从问题中不清楚查找问题的需要是什么。
【解决方案3】:

您好,我会深入研究 Java 的库:

“Java Collections Framework 不包含用于多映射的接口,因为它们并不常用。将值为 List 实例的 Map 用作多映射是一件相当简单的事情。”

来源:https://docs.oracle.com/javase/tutorial/collections/interfaces/map.html

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-10-25
    • 1970-01-01
    • 1970-01-01
    • 2011-08-28
    • 2019-02-19
    • 1970-01-01
    • 1970-01-01
    • 2020-08-12
    相关资源
    最近更新 更多