【问题标题】:Best way to create a hashmap of arraylist创建arraylist哈希图的最佳方法
【发布时间】:2010-11-03 21:31:31
【问题描述】:

我有一百万行 .txt 格式的数据。格式非常简单。对于每一行:

用户 1,值 1 用户2,价值2 用户 3,价值 3 用户 1,值 4 ...

你知道我的意思。对于每个用户,它可能出现多次,或者只出现一次(你永远不知道)。我需要找出每个用户的所有值。因为用户可能随机出现,所以我使用 Hashmap 来做。即:HashMap(key: String, value: ArrayList)。但是要给arrayList添加数据,我必须不断地使用HashMap get(key)来获取arrayList,给它加值,然后放回HashMap。我觉得效率不是很高。有人知道更好的方法吗?

【问题讨论】:

    标签: java data-structures collections arraylist hashmap


    【解决方案1】:

    从 Java 8 开始你可以使用map.computeIfAbsent

    https://docs.oracle.com/javase/8/docs/api/java/util/Map.html#computeIfAbsent-K-java.util.function.Function-

    Collection<String> values = map.computeIfAbsent(user, k -> new ArrayList<>());
    values.add(value);
    

    【讨论】:

      【解决方案2】:

      使用 Google Collections 中的 Multimap。它允许同一个键有多个值

      https://google.github.io/guava/releases/19.0/api/docs/com/google/common/collect/Multimap.html

      【讨论】:

        【解决方案3】:

        如果您不想导入库。

        package util;    
        
        import java.util.ArrayList;    
        import java.util.HashMap;    
        import java.util.List;    
        
        /**    
         * A simple implementation of a MultiMap. This implementation allows duplicate elements in the the    
         * values. (I know classes like this are out there but the ones available to me didn't work).    
         */    
        public class MultiMap<K, V> extends HashMap<K, List<V>> {    
        
          /**    
           * Looks for a list that is mapped to the given key. If there is not one then a new one is created    
           * mapped and has the value added to it.    
           *     
           * @param key    
           * @param value    
           * @return true if the list has already been created, false if a new list is created.    
           */    
          public boolean putOne(K key, V value) {    
            if (this.containsKey(key)) {    
              this.get(key).add(value);    
              return true;    
            } else {    
              List<V> values = new ArrayList<>();    
              values.add(value);    
              this.put(key, values);    
              return false;    
            }    
          }    
        }    
        

        【讨论】:

          【解决方案4】:

          我找不到任何简单的方法。 MultiMap 并不总是可用的选项。所以我写了这个。

          public class Context<K, V> extends HashMap<K, V> {
          
              public V addMulti(K paramK, V paramV) {
                  V value = get(paramK);
                  if (value == null) {
                      List<V> list = new ArrayList<V>();
                      list.add(paramV);
                      put(paramK, paramV);
                  } else if (value instanceof List<?>) {
                      ((List<V>)value).add(paramV);
                  } else {
                      List<V> list = new ArrayList<V>();
                      list.add(value);
                      list.add(paramV);
                      put(paramK, (V) list);
                  }
                  return paramV;
              }
          }
          

          【讨论】:

            【解决方案5】:

            您无需将 ArrayList 重新添加回您的地图。如果 ArrayList 已经存在,那么只需将您的值添加到它。

            改进的实现可能如下所示:

            Map<String, Collection<String>> map = new HashMap<String, Collection<String>>();
            

            在处理每一行时:

            String user = user field from line
            String value = value field from line
            
            Collection<String> values = map.get(user);
            if (values==null) {
                values = new ArrayList<String>();
                map.put(user, values)
            }
            values.add(value);
            

            2014 年 4 月跟进 - 我在 2009 年写了原始答案,当时我对 Google Guava 的了解有限。鉴于 Google Guava 所做的一切,我现在建议使用它的 Multimap 而不是重新发明它。

            Multimap<String, String> values = HashMultimap.create();
            values.put("user1", "value1");
            values.put("user2", "value2");
            values.put("user3", "value3");
            values.put("user1", "value4");
            
            System.out.println(values.get("user1"));
            System.out.println(values.get("user2"));
            System.out.println(values.get("user3"));
            

            输出:

            [value4, value1]
            [value2]
            [value3]
            

            【讨论】:

            • 其他答案都是正确的。我只是不想使用外部库。
            【解决方案6】:

            如前所述,MultiMap 是您的最佳选择。

            根据您的业务需求或对数据文件的限制,您可能需要考虑对其进行一次性排序,以使其更适合加载。

            【讨论】:

            • 这应该是一条评论
            【解决方案7】:

            如果你使用 LinkedList 而不是 ArrayList 会更快,因为 ArrayList 在接近容量时需要调整大小。

            您还需要适当地估计您正在创建的包装集合(HashMap 或 Multimap)的容量,以避免重复重新散列。

            【讨论】:

            • ArrayList 几乎肯定会具有更好的平均性能,即使调整大小也是如此。当您希望所有操作花费大致相同的时间时,LinkedList 是一个不错的选择,例如,它们涉及 UI,并且您不希望用户执行操作时出现随机延迟。
            【解决方案8】:

            我认为你想要的是 Multimap。您可以从 apache 的 commons 集合或 google-collections 中获取它。

            http://commons.apache.org/collections/

            http://code.google.com/p/google-collections/

            " 类似于 Map 的集合,但是 可能关联多个值 用一把钥匙。如果你调用 put(K, V) 两次,使用相同的密钥,但 不同的值,多​​图 包含从键到两者的映射 值。”

            【讨论】:

              【解决方案9】:

              HashMap 中的 ArrayList 值是引用。您不需要“将其放回 HashMap”。您正在对 HashMap 中已作为值存在的对象进行操作。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2011-01-18
                • 1970-01-01
                • 2012-02-09
                • 2010-10-04
                • 2010-09-29
                • 2016-10-06
                • 1970-01-01
                相关资源
                最近更新 更多