【问题标题】:How to add Unique Values to a Hashmap at an Existing Key如何在现有键处向 Hashmap 添加唯一值
【发布时间】:2015-02-18 23:04:40
【问题描述】:

我正在尝试构建一个程序,将运行时间添加到特定位置。然后我将位置和时间存储在哈希图中。当我得到运行时间时,我将它添加到 LinkedList,然后尝试将新更新的 LinkedList 放在 hashmap 的 Key 值处。然而,一旦我搬到一个新的位置,运行时间不会停留在他们设计的位置,所以所有的位置最终都有相同的运行时间。我不太确定我做错了什么。感谢您的帮助。

示例数据: 位置 A:45 秒、43 秒、36 秒 位置 B:51 秒、39 秒

不正确的输出: 位置 A:39 秒、51 秒 位置 B:39 秒、51 秒

正确的输出: 位置 A:36 秒、43 秒、45 秒 位置 B:39 秒、51 秒

    HashMap h = new HashMap();
    LinkedList times = new LinkedList();
    LinkedList newTimes = new LinkedList();


public static void addInformation(HashMap h, LinkedList times, LinkedList    
newTimes) {

   String location = scanner.next();
   Double time = scanner.nextDouble();

   if (h.containsKey(location)){
        for (int i = 0; i < newTimes.size(); i++){
            times.add(newTimes.get(i));
        }
        times.add(time);
        getFastTime(times);
        h.get(location).add(location, times); // cannot resolve add method 
    }else{
        newTimes.clear();
        newTimes.add(time);
        getFastTime(newTimes);
        h.put(location, newTimes);
    }
}
public static void printInformation(HashMap h) {
    Set keySet = h.keySet();  
    for ( Object locationName : keySet) {
        //Use the key to get each value. Repeat for each key.
        System.out.println("Location =" + locationName + " Time =" + 
    h.get(locationName));
    }
}

public static void getFastTime(LinkedList times){
   times.sort(null);
}

【问题讨论】:

  • 虽然您当然可以自己滚动,但 Appachie Commons 和 Google 都提供了 MultiMap 实现,它允许您在同一个键中存储多个值。使用其中之一可能会大大简化您的实施。请参阅此处:stackoverflow.com/questions/14925329/… 了解如何获取它们。

标签: java linked-list hashmap


【解决方案1】:

问题在于 Java 通过引用传递的事实。您没有为不同的位置创建新列表,因此地图中的所有条目都使用相同的列表。您应该阅读此内容,因为它是 Java 的一个基本方面。

接下来,您的集合应该被参数化。您不需要 times 和 newTimes 列表。还要在地图中使用 List 而不是 LinkedList。像这样:

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

并且在方法定义中做同样的事情。还有许多其他问题,例如 printInformation 方法假定对象是字符串,甚至没有强制转换它们。输入未验证。如果输入格式不正确怎么办?应该考虑这一点。此外,变量的命名应该更好。

这样的东西应该可以工作(未经测试。您还必须查看 print 方法以使其与列表一起使用):

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

public static void addInformation(HashMap<String, List<Double>> map) {
    //input should be validated here
    String location = scanner.next();
    Double time = scanner.nextDouble();

    List<Double> timesInMap = map.get(location);
    if (timesInMap != null){
        timesInMap.add(time);
        timesInMap.sort(null);
    }else{
        timesInMap = new ArrayList<Double>();
        timesInMap.add(time);
        map.put(location, timesInMap);
    }
}
public static void printInformation(HashMap<String, List<Double>> map) {
    Set<String> keySet = map.keySet();  
    for (String locationName : keySet) {
        //Use the key to get each value. Repeat for each key.
        System.out.println("Location =" + locationName + " Time =" + 
                map.get(locationName));
    }
}

【讨论】:

  • 您永远不会在地图上putting 新创建的数组列表。正确的方法是使用现有的Multimap 实现或创建自己的实现,然后让您的程序通过其操作使用它。
  • 你说得对,我忘了那句话。更新了我的答案。我不同意正确的方法是使用第三方库。每个键的列表就足够了。在此处查看相关问题:stackoverflow.com/questions/8229473/…
  • 好的,我接受手动这样做是不正确的。也许对于大学的一个项目来说,这是可以的。但是对于生产系统,为什么要重新发明轮子呢?那里的图书馆高效,经过良好测试并且具有良好的界面。实际上,在您已链接的问题的已接受答案下方有一条评论正是如此。但是,正如你所说,你可以自己做。但是,如果您打算多次使用相同的功能,则应将其封装在一个类中,即MyOwnMultimap
  • 我同意。对于更大的系统,我还会考虑使用某种自定义的Multimap。我的意思是,对于这样一个极其简单的项目,没有理由必须使用任何第三方库。
【解决方案2】:

在 Java 中,当您传递参数或获取对象时,实际上是在处理该对象上的 引用。大多数情况下,集合是可变的(即使您也可以创建不可变的),这意味着您可以就地修改集合。 最好使用Generics 来支持强类型,这应该可以解决您的add 方法未解决的问题。

例如,hashmap 应该声明为:

HashMap<String, List<Double>> h = new HashMap<>();

在左侧,它只是声明了 hashmap 应该包含的内容,还没有List&lt;Double&gt; 被实例化。

我不确定您是否需要全局声明 timesnewTimes 列表。对于HashMap&lt;&gt; 中的每个条目,时间值将存储在不同的List&lt;Double&gt; 中。 addInformation 函数可能有以下逻辑:

// Add one (location, time) scanned from input
public static void addInformation(HashMap<String, List<Double> locations,
                                  Scanner scanner) {
   String location = scanner.next();
   Double time = scanner.nextDouble();

   List<Double> times = locations.get(location);
   if (times == null) {
      // this is a new location, create the linkedlist
      // and put it in the hashmap
      times = new LinkedList<Double>();
      locations.put(location, times);
   }
   // add the time to the linkedlist
   times.add(time);
}

在上面的实现中,时间是按插入排序的(第一个元素首先插入)。如果您希望对这个时间值始终进行排序,则可以在每次添加新的(位置、时间)时对列表进行排序,即在 times.add(time) 之后添加以下行:

Collections.sort(times);

排序修改列表 - 您可以在 java doc Collections.sort 中了解更多详细信息。

另一种选择是使用TreeSet&lt;Double&gt; 而不是LinkedList&lt;Double&gt;。元素将保持排序,但不允许重复时间。

如果您需要保留时间值的重复项和已排序的集合,那么您可以使用 TreeMultiset 来做到这一点。

另外,请注意使用Collection.sort 或使用TreeSet 之类的排序集合的顺序可以用Comparator 控制。例如,您可能希望时间按递减 顺序(Double 的自然顺序将递增)。

【讨论】:

    【解决方案3】:

    试试这个代码,你的链接列表是全局定义的,并由所有位置键共享,

    HashMap h = new HashMap();
    public static void addInformation(HashMap h, LinkedList times, LinkedList    
    newTimes) {
    
       String location = scanner.next();
       Double time = scanner.nextDouble();
    
       if (h.containsKey(location)){
            LinkedList times = h.get(location);
            times.add(time);
            getFastTime(times);
    
        }else{
            LinkedList newTimes = new LinkedList();
            newTimes.add(time);
            getFastTime(newTimes);
            h.put(location, newTimes);
        }
    }
    

    【讨论】:

    • 嗯,我仍然收到错误消息。我在我的主函数中启动 LinkedList,然后将它传递给我的 addInformation 方法。如果我在本地定义它们,则每次调用此方法时它们都会重置(我经常这样做)。当我尝试定义 LinkedList 时间时,尝试获取时仍然会出错。抱歉,如果我不理解您的代码。
    • 我刚刚更新了代码,我删除了 h.get(location).add(location, times);当位置存在于 Hashmap 中时,来自代码。您将 LinkList 实例化一次并将其添加到 Hashmap,然后每次需要更新并添加到它时访问它。
    猜你喜欢
    • 2013-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-28
    • 1970-01-01
    • 2013-05-11
    • 2015-01-25
    相关资源
    最近更新 更多