Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/311.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Java中获得HashMap多次出现相同值的次数?_Java_Data Structures_Map_Hashmap - Fatal编程技术网

如何在Java中获得HashMap多次出现相同值的次数?

如何在Java中获得HashMap多次出现相同值的次数?,java,data-structures,map,hashmap,Java,Data Structures,Map,Hashmap,是否有任何简单的方法可以获取存在相同值的键? 或者更重要的是,如何多次获得相同值的数量 考虑hashmap: 1->A 2->A 3->A 4->B 5->C 6->D 7->D 在这里,相同的值不止一次出现3次(A两次,D一次)。这就是我想要的回报 我可以通过keyset/map.values()列表遍历hashmap,但这样做似乎很麻烦。有什么建议或解决办法吗 编辑: 我的背景是,我正在做一个时间表生成器。时隙的数据结构是 {String day-

是否有任何简单的方法可以获取存在相同值的键? 或者更重要的是,如何多次获得相同值的数量

考虑hashmap:

1->A
2->A
3->A
4->B
5->C
6->D
7->D
在这里,相同的值不止一次出现3次(A两次,D一次)。这就是我想要的回报

我可以通过keyset/map.values()列表遍历hashmap,但这样做似乎很麻烦。有什么建议或解决办法吗

编辑: 我的背景是,我正在做一个时间表生成器。时隙的数据结构是

{String day-hour, HashMap<String,Event> Rooms}
{String day hour,HashMap Rooms}
在一天的一小时内,房间地图上会指定一些活动。在检查解决方案的适用性时,我需要知道是否有一名员工在同一时间被分配了多个活动。因此,我想通过values Event.getStaff()检查Rooms map中有多少违规行为

编辑: 这里的值是对象,我不想计算相同对象的出现次数,而是对象的一个字段。事件对象有一个字段staff,我需要计算staff的多次出现次数

我可以通过keyset/map.values()列表遍历hashmap,但这样做似乎很麻烦

它的效率很低,但是如果没有某种多重映射来存储值到键的反向映射,您就不能做很多事情

但是,如果您使用:

Multiset counts=HashMultiSet.create(map.values());
for(Multiset.Entry:counts.entrySet){
if(entry.getCount()>1){
System.out.println(entry.getElement()+“:“+entry.getCount());
}
}

我不知道上下文,但如果您使用多重映射,该怎么办:

Map<String, List<Integer>>

您可以围绕(哈希)映射创建一个包装类,通过修饰put()-remove()方法来维护另一个映射,其中原始映射的值是键,值是出现的次数。然后你只需要实现这个方法来查询

然而,这是相当棘手的!你必须小心不要有指向地图上不再存在的对象的链接。。。这可能导致内存泄漏

此外,必须考虑空值公差

public static class MyCountingMap<K,V> implements Map<K,V> {
  private final Map<K,V> internalMap;
  //hashmap tolerates null as a key!
  private final Map<V,Long> counterMap = new HashMap<V, Long>();

  public MyCountingMap(Map<K, V> internalMap) {
    super();
    this.internalMap = internalMap;
  }


  @Override
  public V put(K key, V value) {
    boolean containedOriginally = internalMap.containsKey(key);

    V origValue = internalMap.put(key, value);

    updateCounterPut(containedOriginally, origValue, value);

    return origValue;
  }

  @Override
  public void putAll(Map<? extends K, ? extends V> m) {
    //now this is the awkward part...
    //this whole thing could be done through a loop and the put() method, 
    //but I'd prefer to use the original implementation...
    for(Map.Entry<? extends K, ? extends V> entry :m.entrySet()) {
      boolean containedOriginally = internalMap.containsKey(entry.getKey());
      V origValue = internalMap.get(entry.getKey());
      updateCounterPut(containedOriginally, origValue, entry.getValue());
    }


    internalMap.putAll(m);
  }

  // this method updates the counter
  private void updateCounterPut(boolean containedOriginally, V origValue, V newValue) {
    //if it was in the map, and it is different than the original, decrement 
    if(containedOriginally && isDifferent(origValue, newValue)) 
    {
      decrement(origValue);
    }

    //if it was NOT in the map, or the value differs
    if(!containedOriginally || isDifferent(origValue, newValue)) {
      increment(newValue);
    }
  }

  // nothing special, just nicer to extract this to a method. Checks if the two values are the same or not.
  private static boolean isDifferent(Object origValue, Object newValue) {
    return ((origValue==null && newValue!=null) || !(origValue!=null && origValue.equals(newValue)));
  }

  //this method returns the counter value for the map value
  public Long getValueCount(V value) {
    return counterMap.get(value);
  }

  @Override
  public V remove(Object key) {
    V toReturn = internalMap.remove(key);
    if(toReturn!=null) {
      decrement(toReturn);
    }
    return toReturn;
  }

  private void increment(V value) {
    Long count = counterMap.get(value);
    if(count == null) {
      count = 0L;
    }
    counterMap.put(value, count+1);
  }

  private void decrement(V value) {
    Long count = counterMap.get(value);
    if(count == null) {
      count = 0L;
    }

    //last! Have to remove reference to prevent memory leak!!
    if(count == 1L) {
      counterMap.remove(value);
    } else {
      counterMap.put(value, count-1);
    }

  }
  //... boring wrapper methods ...
  public void clear() { internalMap.clear(); }
  public boolean containsKey(Object key) { return internalMap.containsKey(key); }
  public boolean containsValue(Object value) { return internalMap.containsValue(value);   }
  public Set<Entry<K, V>> entrySet() { return internalMap.entrySet();    }
  public V get(Object key) { return internalMap.get(key); }
  public boolean isEmpty() { return internalMap.isEmpty(); } 
  public Set<K> keySet() { return internalMap.keySet(); }
  public int size() { return internalMap.size(); }
  public Collection<V> values() { return internalMap.values(); }
}
公共静态类MyCountingMap实现Map{
私人最终地图;
//hashmap允许null作为密钥!
private final Map counterMap=new HashMap();
公共计算地图(地图内部地图){
超级();
this.internalMap=internalMap;
}
@凌驾
公共V输入(K键,V值){
布尔containedorinaly=internalMap.containsKey(键);
V origValue=internalMap.put(键,值);
updateCounterPut(最初包含,origValue,value);
返回原始值;
}
@凌驾

公共void putAll(Map我认为这是一个很好的方式:

int freq = Collections.frequency(map.values(), "A");
返回“3”作为示例。干杯

编辑:很抱歉,我在第一次尝试时误解了这个问题,这应该可以做到:

int k = 0;
Set<String> set = new HashSet<String>(map.values());
for (String s : set) {
   int i = Collections.frequency(map.values(), s);
   k += i > 1 ? i - 1 : 0;
}
intk=0;
Set=newhashset(map.values());
for(字符串s:set){
int i=Collections.frequency(map.values(),s);
k+=i>1?i-1:0;
}
不过,您仍然无法检索实际的钥匙。但这并不是最重要的,对吗?

如何(扩展Jon的答案)

Multiset counts=HashMultiSet.create(map.values());
谓词pred=新谓词(){
公共布尔应用(Map.Entry){
返回counts.count(entry.getValue())>1;
}
}
映射结果=映射.filterEntries(映射,pred);
这将产生一个映射,其中每个键映射到一个重复的值


这个答案仅用于回答问题的第一部分(“不太重要的部分”),以获取具有重复值的键。

上述代码的问题将丢失键/值关系,因此OP将无法获取重复值的键。我将看到在计数>1的多集上执行筛选,然后在值位于筛选集中的位置执行
映射。filterKeys
操作。@JohnB:嗯,OP的“重要”要求是获得相同值出现的次数。尽管有第一句话,关键部分似乎并不那么重要。在我看来,最好避免简单任务使用外部lib,否则您将在项目中得到一百万个JAR来跟踪。当然,除非该lib在许多方面使您的生活更轻松只是one@MånsRolandiDanielsson:根据我的经验,Guava在几乎所有Java项目中都很有用。我无法想象在没有它的情况下用Java编写任何有意义的东西。OP必须对值列表进行硬编码,这不会给出具有重复值的键。这只是得到重复值的计数,它给出了r键或值。你又是对的,但根据最初的问题,这不是这个问题中最重要的事情。我的错,没有看到第二行。请注意,这基本上是一个O(N^2)解决方案。对于一个副本很少的大型地图,它可能会很耗时。当然,这可能是绝对好的-OP只需要知道它。谢谢!但我从来没有使用过Guava或MultiSet,因为我是java的初学者。如果其他方法失败/麻烦,那么我会尝试Guava。顺便说一句,这并不重要;我被计数卡住了,还有你有时候我可能也需要钥匙,现在我真的需要了。
int freq = Collections.frequency(map.values(), "A");
int k = 0;
Set<String> set = new HashSet<String>(map.values());
for (String s : set) {
   int i = Collections.frequency(map.values(), s);
   k += i > 1 ? i - 1 : 0;
}
Multiset<V> counts = HashMultiSet.create(map.values());
Predicate<Map.Entry<K,V>> pred = new Predicate<Map.Entry<K,V>>(){
   public boolean apply(Map.Entry<K,V> entry){
       return counts.count(entry.getValue()) > 1;
   }
}
Map<K,V> result = Maps.filterEntries(map, pred);