【问题标题】:HashMap with multiple values under the same keyHashMap在同一个键下有多个值
【发布时间】:2011-06-24 19:38:32
【问题描述】:

我们是否可以实现一个键和两个值的HashMap。就像 HashMap 一样?

请帮助我,也告诉(如果没有办法)任何其他方式来实现以一个为键的三个值的存储?

【问题讨论】:

标签: java


【解决方案1】:

不,不仅仅是HashMap。您基本上需要从键到值集合的 HashMap

如果您乐于使用外部库,GuavaMultimap 中就拥有这个概念,并实现了诸如ArrayListMultimapHashMultimapLinkedHashMultimap 等。

Multimap<String, Integer> nameToNumbers = HashMultimap.create();

System.out.println(nameToNumbers.put("Ann", 5)); // true
System.out.println(nameToNumbers.put("Ann", 5)); // false
nameToNumbers.put("Ann", 6);
nameToNumbers.put("Sam", 7);

System.out.println(nameToNumbers.size()); // 3
System.out.println(nameToNumbers.keySet().size()); // 2

【讨论】:

  • @Deepak:搜索番石榴多图示例,您会找到示例代码。
  • @Deepak:基本上你会自己构建类似ArrayListMultimap 的东西......或者只是使用HashMap&lt;String, List&lt;Integer&gt;&gt; 或其他什么。基本上,每次第一次添加值时,您都需要创建一个空列表。
  • 你有HashMap&lt;String, List&lt;Integer&gt;&gt;的工作示例
  • @Deepak:我建议您尝试自己创建一个示例,如果遇到困难,请尽可能提出包括代码在内的问题。这样你会学到更多。
  • Multimap multimap = ArrayListMultimap.create(); multimap.put("key", "value");
【解决方案2】:

是和不是。解决方案是为您的值构建一个 Wrapper 类,其中包含与您的键对应的 2 个(3 个或更多)值。

【讨论】:

    【解决方案3】:

    你可以:

    1. 使用以列表作为值的映射。 Map&lt;KeyType, List&lt;ValueType&gt;&gt;
    2. 创建一个新的包装器类并将该包装器的实例放置在映射中。 Map&lt;KeyType, WrapperType&gt;
    3. 使用类元组(节省创建大量包装器)。 Map&lt;KeyType, Tuple&lt;Value1Type, Value2Type&gt;&gt;
    4. 并排使用多个地图。

    示例

    1.以列表为值的映射

    // create our map
    Map<String, List<Person>> peopleByForename = new HashMap<>();    
    
    // populate it
    List<Person> people = new ArrayList<>();
    people.add(new Person("Bob Smith"));
    people.add(new Person("Bob Jones"));
    peopleByForename.put("Bob", people);
    
    // read from it
    List<Person> bobs = peopleByForename["Bob"];
    Person bob1 = bobs[0];
    Person bob2 = bobs[1];
    

    这种方法的缺点是列表不能精确地绑定到两个值。

    2。使用包装类

    // define our wrapper
    class Wrapper {
        public Wrapper(Person person1, Person person2) {
           this.person1 = person1;
           this.person2 = person2;
        }
    
        public Person getPerson1 { return this.person1; }
        public Person getPerson2 { return this.person2; }
    
        private Person person1;
        private Person person2;
    }
    
    // create our map
    Map<String, Wrapper> peopleByForename = new HashMap<>();
    
    // populate it
    peopleByForename.put("Bob", new Wrapper(new Person("Bob Smith"),
                                            new Person("Bob Jones"));
    
    // read from it
    Wrapper bobs = peopleByForename.get("Bob");
    Person bob1 = bobs.getPerson1;
    Person bob2 = bobs.getPerson2;
    

    这种方法的缺点是您必须为所有这些非常简单的容器类编写大量样板代码。

    3.使用元组

    // you'll have to write or download a Tuple class in Java, (.NET ships with one)
    
    // create our map
    Map<String, Tuple2<Person, Person> peopleByForename = new HashMap<>();
    
    // populate it
    peopleByForename.put("Bob", new Tuple2(new Person("Bob Smith",
                                           new Person("Bob Jones"));
    
    // read from it
    Tuple<Person, Person> bobs = peopleByForename["Bob"];
    Person bob1 = bobs.Item1;
    Person bob2 = bobs.Item2;
    

    这是我认为最好的解决方案。

    4.多张地图

    // create our maps
    Map<String, Person> firstPersonByForename = new HashMap<>();
    Map<String, Person> secondPersonByForename = new HashMap<>();
    
    // populate them
    firstPersonByForename.put("Bob", new Person("Bob Smith"));
    secondPersonByForename.put("Bob", new Person("Bob Jones"));
    
    // read from them
    Person bob1 = firstPersonByForename["Bob"];
    Person bob2 = secondPersonByForename["Bob"];
    

    此解决方案的缺点是这两个地图相关性并不明显,程序错误可能导致两个地图不同步。

    【讨论】:

    • 嗨,保罗……你能说得更清楚一点吗……?举个例子……?
    • @vidhya:哪一个特别适合您的问题?您的多个对象是相同类型还是不同类型?
    • 示例实际上会很棒。
    • @Paul,#3 的任何简单示例代码Map&lt;KeyType, Tuple&lt;Value1Type, Value2Type&gt;&gt;
    • @CoolMind 我相信人们可以解决错误:或者您可以纠正它们?
    【解决方案4】:
    【解决方案5】:

    看看来自 guava-libraries 的 Multimap 及其实现 - HashMultimap

    类似于 Map 的集合,但可以将多个值与单个键相关联。如果您使用相同的键但值不同的两次调用 put(K, V),则多重映射包含从键到两个值的映射。

    【讨论】:

      【解决方案6】:

      我无法回复 Paul 的评论,所以我在这里为 Vidhya 创建新评论:

      包装器将是我们想要存储为值的两个类的SuperClass

      在包装类内部,我们可以将关联作为两个类对象的实例变量对象。

      例如

      class MyWrapper {
      
       Class1 class1obj = new Class1();
       Class2 class2obj = new Class2();
      ...
      }
      

      而在HashMap中我们可以这样写,

      Map<KeyObject, WrapperObject> 
      

      WrapperObj 将有类变量:class1Obj, class2Obj

      【讨论】:

        【解决方案7】:

        另一个不错的选择是使用来自 Apache Commons 的 MultiValuedMap。查看页面顶部的所有已知的实现类,了解专门的实现。

        例子:

        HashMap<K, ArrayList<String>> map = new HashMap<K, ArrayList<String>>()
        

        可以替换为

        MultiValuedMap<K, String> map = new MultiValuedHashMap<K, String>();
        

        所以,

        map.put(key, "A");
        map.put(key, "B");
        map.put(key, "C");
        
        Collection<String> coll = map.get(key);
        

        将导致集合 coll 包含“A”、“B”和“C”。

        【讨论】:

          【解决方案8】:

          我使用Map&lt;KeyType, Object[]&gt; 将多个值与 Map 中的一个键相关联。这样,我可以存储与键关联的多个不同类型的值。您必须小心维护从 Object[] 插入和检索的正确顺序。

          示例: 考虑一下,我们要存储学生信息。关键是 id,而我们想存储与学生关联的姓名、地址和电子邮件。

                 //To make entry into Map
                  Map<Integer, String[]> studenMap = new HashMap<Integer, String[]>();
                  String[] studentInformationArray = new String[]{"name", "address", "email"};
                  int studenId = 1;
                  studenMap.put(studenId, studentInformationArray);
          
                  //To retrieve values from Map
                  String name = studenMap.get(studenId)[1];
                  String address = studenMap.get(studenId)[2];
                  String email = studenMap.get(studenId)[3];
          

          【讨论】:

          • 对我来说这是最好的答案。它更简单、更简洁、更不抽象。
          【解决方案9】:
          HashMap<Integer,ArrayList<String>> map = new    HashMap<Integer,ArrayList<String>>();
          
          ArrayList<String> list = new ArrayList<String>();
          list.add("abc");
          list.add("xyz");
          map.put(100,list);
          

          【讨论】:

            【解决方案10】:

            你可以隐式地做到这一点。

            // Create the map. There is no restriction to the size that the array String can have
            HashMap<Integer, String[]> map = new HashMap<Integer, String[]>();
            
            //initialize a key chosing the array of String you want for your values
            map.put(1, new String[] { "name1", "name2" });
            
            //edit value of a key
            map.get(1)[0] = "othername";
            

            这是非常简单和有效的。 如果您想要不同类的值,可以执行以下操作:

            HashMap<Integer, Object[]> map = new HashMap<Integer, Object[]>();
            

            【讨论】:

              【解决方案11】:

              为了记录,纯JDK8的解决方案是使用Map::compute方法:

              map.compute(key, (s, strings) -> strings == null ? new ArrayList<>() : strings).add(value);
              

              public static void main(String[] args) {
                  Map<String, List<String>> map = new HashMap<>();
              
                  put(map, "first", "hello");
                  put(map, "first", "foo");
                  put(map, "bar", "foo");
                  put(map, "first", "hello");
              
                  map.forEach((s, strings) -> {
                      System.out.print(s + ": ");
                      System.out.println(strings.stream().collect(Collectors.joining(", ")));
                  });
              }
              
              private static <KEY, VALUE> void put(Map<KEY, List<VALUE>> map, KEY key, VALUE value) {
                  map.compute(key, (s, strings) -> strings == null ? new ArrayList<>() : strings).add(value);
              }
              

              有输出:

              bar: foo
              first: hello, foo, hello
              

              请注意,为确保在多个线程访问此数据结构的情况下保持一致性,例如需要使用ConcurrentHashMapCopyOnWriteArrayList

              【讨论】:

              • 最好使用computeIfAbsentmap.computeIfAbsent(key, k -&gt; new ArrayList&lt;&gt;()).add(value);
              【解决方案12】:

              可以使用identityHashMap来完成,条件是键比较将由==运算符完成,而不是equals()。

              【讨论】:

                【解决方案13】:

                我更喜欢以下方式来存储任意数量的变量,而无需创建单独的类。

                final public static Map<String, Map<String, Float>> myMap    = new HashMap<String, Map<String, Float>>();
                

                【讨论】:

                  【解决方案14】:
                  String key= "services_servicename"
                  
                  ArrayList<String> data;
                  
                  for(int i = 0; i lessthen data.size(); i++) {
                      HashMap<String, String> servicesNameHashmap = new HashMap<String, String>();
                      servicesNameHashmap.put(key,data.get(i).getServiceName());
                      mServiceNameArray.add(i,servicesNameHashmap);
                  }
                  

                  我得到了最好的结果。

                  你只需要创建新的HashMap 就像

                  HashMap<String, String> servicesNameHashmap = new HashMap<String, String>();
                  

                  在您的 for 循环中。它会产生相同的效果,就像相同的键和多个值一样。

                  【讨论】:

                    【解决方案15】:

                    我已经习惯了只在 Objective C 中使用数据字典来执行此操作。在 Java for Android 中很难获得类似的结果。我最终创建了一个自定义类,然后只为我的自定义类做一个哈希图。

                    public class Test1 {
                    @Override
                    protected void onCreate(Bundle savedInstanceState) {
                        super.onCreate(savedInstanceState);
                        setContentView(R.layout.addview);
                    
                    //create the datastring
                        HashMap<Integer, myClass> hm = new HashMap<Integer, myClass>();
                        hm.put(1, new myClass("Car", "Small", 3000));
                        hm.put(2, new myClass("Truck", "Large", 4000));
                        hm.put(3, new myClass("Motorcycle", "Small", 1000));
                    
                    //pull the datastring back for a specific item.
                    //also can edit the data using the set methods.  this just shows getting it for display.
                        myClass test1 = hm.get(1);
                        String testitem = test1.getItem();
                        int testprice = test1.getPrice();
                        Log.i("Class Info Example",testitem+Integer.toString(testprice));
                    }
                    }
                    
                    //custom class.  You could make it public to use on several activities, or just include in the activity if using only here
                    class myClass{
                        private String item;
                        private String type;
                        private int price;
                    
                        public myClass(String itm, String ty, int pr){
                            this.item = itm;
                            this.price = pr;
                            this.type = ty;
                        }
                    
                        public String getItem() {
                            return item;
                        }
                    
                        public void setItem(String item) {
                            this.item = item;
                        }
                    
                        public String getType() {
                            return item;
                        }
                    
                        public void setType(String type) {
                            this.type = type;
                        }
                    
                        public int getPrice() {
                            return price;
                        }
                    
                        public void setPrice(int price) {
                            this.price = price;
                        }
                    
                    }
                    

                    【讨论】:

                      【解决方案16】:

                      我们可以创建一个具有多个键或值的类,并且该类的对象可以用作映射中的参数。 可以参考https://stackoverflow.com/a/44181931/8065321

                      【讨论】:

                        【解决方案17】:

                        最简单的方法是使用谷歌收藏库:

                        import com.google.common.collect.ArrayListMultimap;
                        import com.google.common.collect.Multimap;
                        
                        public class Test {
                        
                            public static void main(final String[] args) {
                        
                                // multimap can handle one key with a list of values
                                final Multimap<String, String> cars = ArrayListMultimap.create();
                                cars.put("Nissan", "Qashqai");
                                cars.put("Nissan", "Juke");
                                cars.put("Bmw", "M3");
                                cars.put("Bmw", "330E");
                                cars.put("Bmw", "X6");
                                cars.put("Bmw", "X5");
                        
                                cars.get("Bmw").forEach(System.out::println);
                        
                                // It will print the:
                                // M3
                                // 330E
                                // X6
                                // X5
                            }
                        
                        }
                        

                        maven 链接:https://mvnrepository.com/artifact/com.google.collections/google-collections/1.0-rc2

                        更多信息:http://tomjefferys.blogspot.be/2011/09/multimaps-google-guava.html

                        【讨论】:

                          【解决方案18】:

                          如果您使用 Spring 框架。有:org.springframework.util.MultiValueMap

                          创建不可修改的多值映射:

                          Map<String,List<String>> map = ...
                          MultiValueMap<String, String> multiValueMap = CollectionUtils.toMultiValueMap(map);
                          

                          或使用org.springframework.util.LinkedMultiValueMap

                          【讨论】:

                            【解决方案19】:

                            使用 Java 收集器

                            // Group employees by department
                            Map<Department, List<Employee>> byDept = employees.stream()
                                                .collect(Collectors.groupingBy(Employee::getDepartment));
                            

                            部门是你的关键

                            【讨论】:

                              【解决方案20】:
                               import java.io.*;
                               import java.util.*;
                              
                               import com.google.common.collect.*;
                              
                               class finTech{
                              public static void main(String args[]){
                                     Multimap<String, String> multimap = ArrayListMultimap.create();
                                     multimap.put("1","11");
                                     multimap.put("1","14");
                                     multimap.put("1","12");
                                     multimap.put("1","13");
                                     multimap.put("11","111");
                                     multimap.put("12","121");
                                      System.out.println(multimap);
                                      System.out.println(multimap.get("11"));
                                 }                                                                                            
                               }                                                                    
                              

                              输出:

                                   {"1"=["11","12","13","14"],"11"=["111"],"12"=["121"]}
                              
                                    ["111"]
                              

                              这是用于实用功能的 Google-Guava 库。这是必需的解决方案。

                              【讨论】:

                              • 这是一个有效的解决方案,我已经多次使用过这种方法。
                              • 是的,它可以工作,但它以 [] 格式显示数据我想要这些项目一项一项如何让我卡在这里
                              【解决方案21】:

                              Apache Commons 集合类可以在同一个键下实现多个值。

                              MultiMap multiMapDemo = new MultiValueMap();
                              
                              multiMapDemo .put("fruit", "Mango");
                              multiMapDemo .put("fruit", "Orange");
                              multiMapDemo.put("fruit", "Blueberry");
                              
                              System.out.println(multiMapDemo.get("fruit"));
                              

                              Maven 依赖

                              <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 -->
                              <dependency>
                                 <groupId>org.apache.commons</groupId>
                                 <artifactId>commons-collections4</artifactId>
                                 <version>4.4</version>
                              </dependency>
                              

                              【讨论】:

                              猜你喜欢
                              • 2012-05-17
                              • 2018-09-08
                              • 2014-08-18
                              • 1970-01-01
                              • 2020-09-29
                              • 1970-01-01
                              • 1970-01-01
                              • 2015-06-28
                              • 1970-01-01
                              相关资源
                              最近更新 更多