【问题标题】:How to count the number of unique values in HashMap?如何计算HashMap中唯一值的数量?
【发布时间】:2018-02-20 11:51:16
【问题描述】:

我在这里看到了很多关于如何使用 ArrayList 和 HashMaps 的不错的解决方案,但关键是我仍然无法解决我的问题。

所以,这个想法是很少有人喝啤酒、葡萄酒和可乐。所以,它看起来像这样(例如):

Steve wine
Steve cola
Ben cola
Frank wine
Ben cola
Ben cola
Frank wine

最后,我需要计算他们每个人喝了多少杯饮料。所以,答案应该是这样的:

Steve wine 1
Steve cola 1
Ben cola 3
Frank wine 2

我的想法是创建一个对象 Person(String name, String Drink)。然后我把所有的人放到 ArrayList 中。之后我创建了 HashMap 并想在 key 不存在时添加一个新的 Person ,如果 key 已经存在则递增到 1 。

    Map<Person, Integer> map = new HashMap<Person, Integer>();

    for (Person p : persons)
    {
        if (map.containsKey(p)) {
            map.put(p, map.get(p)+1);
        } else {
            map.put(p,1);
        }
   }

它不起作用。它只是返回给我这样的结果:

 Steve wine 1
 Steve cola 1
 Ben cola 1
 Frank wine 1
 Ben cola 1
 Ben cola 1
 Frank wine 1

所以,据我所知,这应该是其他一些技巧。也许您还可以告诉任何其他关于如何计算饮料杯数而不是使用 HashMap 的想法? 非常感谢!

【问题讨论】:

标签: java arraylist hashmap


【解决方案1】:

Person Object 存储为 Key 是错误的。

你必须存储人名,一个字符串作为键,它会正常工作。

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

    for (Person p : persons)
    {
        if (map.containsKey(p.getName())) {
            map.put(p.getName(), map.get(p)+1);
        } else {
            map.put(p.getName(),1);
        }
   }

【讨论】:

  • 它是Map&lt;Person, Integer&gt;,那不是很好吗?
  • 不,不是,你有两个选择,1.使用字符串(名称)作为键。要么。 2. 使用 Person 作为键,但覆盖 Person 类中的 hashcode() 和 equals() 方法。
  • @Seelenvirtuose 请再次检查,它已更新。并请恢复您的-1。而不是纠正你是对答案投反对票。
  • @Seelenvirtuose 请检查第一句话,已更正。所以如果你能把-1拿回来会更好。
  • 重点是这个人的名字和他的饮料。如果我只用他的名字,我想关于饮料的信息会丢失。
【解决方案2】:

覆盖 Person 类中的 hashcode 和 equals 方法

【讨论】:

    【解决方案3】:
    int count = Collections.frequency("your collection", "Your Value");
    

    我的意思是这样说的:

    ArrayList<String> list = new ArrayList<>();
    list.add("Steve wine");
    list.add("Steve cola");
    list.add("Ben cola");
    list.add("Frank wine");
    list.add("Ben cola");
    list.add("Ben cola");
    list.add("Frank wine");
    
    System.out.println(Collections.frequency(list, "Steve wine"));
    
    System.out.println(Collections.frequency(list, "Ben cola"));
    

    【讨论】:

    • 什么是“你的价值”?我不知道这些人的名字,也不知道他们事先喝了什么。
    • 输入将是“史蒂夫酒”
    • 这行不通,因为我不知道列表中有什么。想象一下,这是调酒师提供的信息(只是一个例子)作为文本文件。晚上大约有 200 人在喝酒。所以,我不能真正使用频率,因为我不知道喝过的饮料的名称。
    • @Boris 如果您正在寻找频率,那么您必须具有任何输入属性才能获得计数。让我们在您的示例中说,如果调酒师正在寻找频率,那么他应该知道饮酒者或饮酒者。即使您有数据文件,也必须在任何集合中都有数据。
    • 是的,或许将集合中的每个成员一个一个取出,使用频数法,也是一种解决方案。你说得对。谢谢。
    【解决方案4】:

    首先,我建议您注意自己的命名。在您的情况下,真正关键的是订单而不是人(因为史蒂夫可乐和史蒂夫葡萄酒不同,您不应该将其命名为人)。

    之后: containsKey 将使用从 Object 类继承的 hashcode 方法,如果你不在你的类中重写它。 Object 类的哈希码可能会为您的实例提供不同的哈希码,因此您应该在您的类中覆盖它,例如如果您连接名称和饮料(这是您订单的唯一标识符)并在该字符串上调用哈希码方法,则可以创建可接受的哈希码方法。

    【讨论】:

      【解决方案5】:

      在您的 Person 类中重写 equalshascode 方法是解决问题的方法。

      假设你有带有参数 namedrink 的 Person 类,那么你可以使用 Eclipse 等 IDE 为你生成 hashcode 和 equals 方法

      见以下代码:

      public class Person {
            private String name;
            private String drink;
      
            public String getName() {
                  return name;
            }
      
            public void setName(String name) {
                  this.name = name;
            }
      
            public String getDrink() {
                  return drink;
            }
      
            public void setDrink(String drink) {
                  this.drink = drink;
            }
      
            @Override
            public int hashCode() {
                  final int prime = 31;
                  int result = 1;
                  result = prime * result + ((drink == null) ? 0 : drink.hashCode());
                  result = prime * result + ((name == null) ? 0 : name.hashCode());
                  return result;
            }
      
            @Override
            public boolean equals(Object obj) {
                  if (this == obj)
                        return true;
                  if (obj == null)
                        return false;
                  if (getClass() != obj.getClass())
                        return false;
                  Person other = (Person) obj;
                  if (drink == null) {
                        if (other.drink != null)
                              return false;
                  } else if (!drink.equals(other.drink))
                        return false;
                  if (name == null) {
                        if (other.name != null)
                              return false;
                  } else if (!name.equals(other.name))
                        return false;
                  return true;
            }
      }
      

      【讨论】:

      • 是的,现在可以了。谢谢!我是 Java 编程新手,以前从未尝试过覆盖 HashCode 方法。我想这对于任何类型的问题来说都是一个很好的、更通用的解决方案。
      【解决方案6】:

      你必须重写 Person 类中的 equals 和 hashCode 方法。下面是示例代码:

      class Person {
      
        private String name;
        private String drink;
      
        public Person(String name, String drink) {
          super();
          this.name = name;
          this.drink = drink;
        }
      
        @Override
        public int hashCode() {
      
          return this.getName().hashCode();
        }
      
        @Override
        public boolean equals(Object obj) {
      
          if (obj == this)
              return true;
      
          if (!(obj instanceof Person)) {
              return false;
          }
          Person person = (Person) obj;
      
          return person.getName().equals(this.name);
        }
        ....getters and setters
        ....toString method
      }
      

      在此之后,如果您尝试运行您的代码,它肯定会为我工作,因为下面的代码输出是

          Map<Person, Integer> map = new HashMap<>();
      
          for (Person p : persons)
          {
              if (map.containsKey(p)) {
                  map.put(p, map.get(p)+1);
              } else {
                  map.put(p,1);
              }
         }
      
         for(Map.Entry<Person, Integer> person : map.entrySet()){
             System.out.println(person.getKey()+"  "+person.getValue());
         }
      

      输出:

      Person [name=Steve, drink=wine]  2
      Person [name=Ben, drink=cola]  3
      Person [name=Frank, drink=wine]  2
      

      希望对你有所帮助。

      【讨论】:

        【解决方案7】:

        如果你可以使用 Java 8 流,这是一个聪明的解决方案:

            List<Person> people = Arrays.asList(new Person("Steve", "wine"), new Person("Steve", "cola"),
                    new Person("Ben", "cola"), new Person("Ben", "cola"), new Person("Steve", "wine"),
                    new Person("Steve", "wine"));
        
            Map<Person, Long> map = people.stream()
                    .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
        

        编辑: 要减少代码,您可以像这样静态导入方法:

        import static java.util.stream.Collectors.groupingBy;
        import static java.util.stream.Collectors.counting;
        import static java.util.function.Function.identity;
        

        然后代码如下所示:

        Map<Person, Long> map = people
                        .stream()
                        .collect(groupingBy(identity(), counting()));
        

        【讨论】:

        • 非常好的解决方案,只需 1 行代码!但老实说,我不明白这行代码到底发生了什么。
        【解决方案8】:

        键在哈希映射或字典 (C#) 中应该是唯一的。这种情况下插入钥匙本身需要结合姓名和饮料。在这里用 C# 给出解决方案。希望对您有所帮助。

        public class Person
        {
            public string Name { get; set; }
            public string Drink { get; set; }
        }
        
        class Program
        {
            static void Main(string[] args)
            {
                List<Person> persons = new List<Person>();
                persons.Add(new Person() { Name = "Steve", Drink = "Tea" });
                persons.Add(new Person() { Name = "Bell", Drink = "Milk" });
                persons.Add(new Person() { Name = "Bell", Drink = "Milk" });
                persons.Add(new Person() { Name = "Bell", Drink = "Milk" });
                persons.Add(new Person() { Name = "Steve", Drink = "Milk" });
                Dictionary<string, int> output = new Dictionary<string, int>();
                foreach(var p in persons)
                {
                    string key = p.Name + ":" + p.Drink;
                    if(output.ContainsKey(key))
                    {
                        output[key]++;
                    }
                    else
                    {
                        output.Add(key,1);
                    }
                }
                foreach(var k in output)
                {
                    string[] split = k.Key.Split(':');
                    Console.WriteLine(string.Format("{0} {1} {2}", split[0],split[1],k.Value.ToString()));
                }
            }
        }
        

        【讨论】:

        • 这不是 OP 使用的语言 - 这对他没有帮助,因为在 Java 中实现是不同的。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-09-10
        • 2021-07-29
        • 1970-01-01
        • 2018-03-11
        • 1970-01-01
        相关资源
        最近更新 更多