2011-10-04 26 views
0

一個基本問題的OK位在這裏找到在HashSet中最常見的價值,但我想知道什麼是最好的方式去這...的Java

我有我添加的對象,在HashSet的。如果add()方法不存在,add()方法將只添加一個對象。但我想要做的就是添加所有對象,然後在最後得到下面的結果..

的獨特-Number(不同的)對象
對象-The平均頻率

有人能指出我正確的方向?

在此先感謝

回答

2

HashSet是不是真的適合用於跟蹤個別情況,但HashMap幾乎是完美的。

import java.util.HashMap; 
import java.util.Map; 

public class Count<K, V> extends HashMap<K, V> { 

    // Counts unique objects 
    public void add(K o) { 
     int count = this.containsKey(o) ? ((Integer)this.get(o)).intValue() + 1 : 1; 
     super.put(o, (V) new Integer(count)); 
    } 

    // Demonstration 
    public static void main(String[] args) { 

     Count<Object, Integer> c = new Count<Object, Integer>(); 

     String one = "one"; 
     String two = "two"; 
     String six = "six"; 

     c.add(one); 
     c.add(two); 
     c.add(two); 
     c.add(six); 
     c.add(six); 
     c.add(six); 

     System.out.println("Number of distinct objects: " + c.size()); 

     System.out.println("Frequency of different objects: "); 

     for (Map.Entry<Object, Integer> entry : c.entrySet()) { 
      System.out.println(entry.getKey() + " - " + entry.getValue()); 
     } 
    } 
} 

運行時,這個獨立的片斷將輸出

Number of distinct objects - 3 
Frequency of different objects: 
two - 2 
one - 1 
six - 3 
+0

這正是我所追求的...並找到平均值,是否有一個更有效的方法,而不是迭代通過地圖? – DaveB

+0

@DaveB:你真的*需要個人計數嗎?如果是這樣,這絕對是正確的方法。如果不是,我*認爲*我是你的。 –

+0

@DaveB - 此代碼片段輸出單個對象的頻率,而不是[平均值](http://en.wikipedia.org/wiki/Average)。當談到效率時,一個簡單的for循環就是O(n)[複雜類](http://en.wikipedia.org/wiki/Complexity_class),它非常有效。此外,讀取動態地圖的所有條目時不需要進行某種迭代,這是不可能的。 – Saul

1

不同的對象的數量將只是隨後的散列集的大小。

根據你的意思是「平均頻率」,你可以用source.size()/set.size() ...(可能是將其中一個操作數強制爲double以強制浮點運算)。如果你能用一些例子詳細說明你需要什麼,我們可能會幫助更多。

+0

喬恩,你太字面。 OP真的意味着一張地圖,而不是一套。他的意圖很明確。他的方法很天真。 – Bohemian

+0

@Bohemian:說實話,目前我的意圖*並不清楚。我們是否知道OP確實需要每個項目的計數? –

+0

@喬恩我說的是平均數通用對象 – DaveB

7

使用HashMap。使用條目作爲鍵,並將它們映射到Integer以保持計數。

編輯:您可能想要包裝HashMap,以確保每次添加或刪除對象時,計數器都會被適當修改。
爲了讓你開始:

class MapWrapper<Key> 
{ 
    private Map<Key,Integer> map = new HashMap<Key, Integer>(); 

    void add(Key key) 
    { 
     Integer n = map.get(key); 
     if (n == null) 
     { 
      map.put(key, 1); 
     } 
     else 
     { 
      map.put(key, new Integer(n + 1)); 
     } 
    } 

    int occurrences(Key k) 
    { 
     Integer n = map.get(k); 
     if (n == null) 
     { 
      return 0; 
     } 
     else 
     { 
      return n; 
     } 
    } 
} 
+0

我將刪除containsKey檢查,並簡單地調用get(),然後檢查它是否返回null。這避免了執行兩個查找。 – Adamski

+0

@Adamski好點,我修改了代碼。 –

+0

非常感謝,那是我之後 – DaveB

0

您可以只用(哈希)地圖而不是保持計數爲每個不同的對象值在地圖上,或者您可以繼續使用一組,但地方統計所有來電添加。

插入的對象總數是您計算的數量或映射中所有值的總和(迭代EntrySet)。不同對象的數量始終是您的地圖/集的大小()和平均值。頻率明顯是商。

0

對於這樣的情況下,我用我自己的實現地圖界面:

/* 
* Providers easily work with maps of lists 
* */ 
public interface ManyValuedMap<K, V> extends Cloneable, Map<K, List<V>>, Serializable{ 

    public List<V> put(K key, V... values); 
    public void clear(K key); 
    public ManyValuedMap<K, V> clone(); 
    public void sort(Comparator<? super V> c); 
    public List<V> getAllValues(); 
    public Collection<List<V>> values(Comparator<? super K> c); 
    public void lock(); 
    public Map<K, List<V>> toMap(); 

} 

與實現

/** 
* in ManyValuedMap can be stored lists of elements identificated by some key 
* */ 
public class ManyValuedHashMap<K, V> implements ManyValuedMap<K, V>, Serializable { 

    //linked hash map guarantees right key order 
    private Map<K, List<V>> map = new LinkedHashMap<K, List<V>>(); 
    private boolean isNeedToCheckUniqueness; 
    private boolean lock = false; 

    /** 
    * @param needToCheckUniqueness if true then every time when element added uniqueness will be checked 
    * */ 
    public ManyValuedHashMap(boolean needToCheckUniqueness) { 
     isNeedToCheckUniqueness = needToCheckUniqueness; 
    } 

    public ManyValuedHashMap() { 
     this(false); 
    } 

    public ManyValuedHashMap<K, V> put2 (K key, List<V> newValues) { 
     put(key, newValues); 
     return this; 
    } 

    public List<V> put (K key, List<V> newValues) { 
     if (newValues == null) { 
      return put(key, (V)null); 
     } else if (newValues.isEmpty()) { 
      return put(key, (V)null); 
     } else { 
      //noinspection unchecked 
      return put(key, (V[])newValues.toArray()); 
     } 
    } 

    public List<V> put(K key, V... newValues) { 
     checkLock(); 
     List<V> curValues = null; 
     if (newValues != null && key != null) { 
      curValues = this.map.get(key); 

      if (curValues == null) { 
       //new values - add 
       curValues = new ArrayList<V>(); 
       curValues.addAll(Arrays.asList(newValues)); 
       this.map.put(key, curValues); 
      } else { 
       // for this key values were added 
       if (isNeedToCheckUniqueness) { 
        //if is need to check uniqueness - check 
        Integer index; 
        for (V newValue : newValues) { 
         index = null; 
         for (int i = 0; i < curValues.size(); i++) { 
          if (curValues.get(i).equals(newValue)) { 
           index = i; 
           break; 
          } 
         } 
         if (index == null) { 
          curValues.add(newValue); 
         } /*else { 
          //no need to add 
          //this value is already stored in map 
         }*/ 
        } 
       } else { 
        //otherwise add 
        curValues.addAll(Arrays.asList(newValues)); 
       } 
      } 
     } else if (key != null) { 
      curValues = this.map.get(key); 

      if (curValues == null) { 
       curValues = new ArrayList<V>(); 
       this.map.put(key, curValues); 
      } 
     } 

     return curValues; 
    } 

    public boolean containsValue(Object value) { 
     boolean result = false; 
     for (List<V> values : this.map.values()) { 
      for (V v : values) { 
       if (v.equals(value)) { 
        result = true; 
        break; 
       } 
      } 
      if (result) { 
       break; 
      } 
     } 
     return result; 
    } 

    public List<V> get(Object key) { 
     return this.map.get(key); 
    } 

    public boolean containsKey(Object key) { 
     return this.map.containsKey(key); 
    } 

    public boolean isEmpty() { 
     return this.map.isEmpty(); 
    } 

    public int size() { 
     int size = 0; 
     for (List<V> vs : map.values()) { 
      size += vs.size(); 
     } 
     return size; 
    } 

    public List<V> remove(Object key) { 
     checkLock(); 
     return this.map.remove(key); 
    } 

    @Override 
    public void putAll(Map<? extends K, ? extends List<V>> m) { 
     checkLock(); 
     this.map.putAll(m); 
    } 

    public void clear() { 
     checkLock(); 
     this.map.clear(); 
    } 

    @Override 
    public void clear(K key) { 
     checkLock(); 
     List<V> curValues = this.map.get(key); 
     if (curValues != null) { 
      curValues.clear(); 
     } 
    } 

    public Set<K> keySet() { 
     return this.map.keySet(); 
    } 

    public Collection<List<V>> values() { 
     return this.map.values(); 
    } 

    public Set<Map.Entry<K, List<V>>> entrySet() { 
     return this.map.entrySet(); 
    } 

    public Map<K, List<V>> toMap() { 
     return new HashMap<K, List<V>>(map); 
    } 

    @Override 
    public ManyValuedHashMap<K, V> clone() { 
     ManyValuedHashMap<K, V> clone = null; 
     try { 
      //noinspection unchecked 
      clone = (ManyValuedHashMap<K, V>)super.clone(); 
      //IMPORTANT: NOT DEEP CLONE 
      //noinspection unchecked 
      clone.map = new LinkedHashMap<K, List<V>>(); 
      clone.map.putAll(this.map); 
     } catch (CloneNotSupportedException e) { 
      Logger.getLogger(this.getClass()).error(e.getMessage(), e); 
     } 
     return clone; 
    } 

    @Override 
    public void sort(Comparator<? super V> c) { 
     for (List<V> list : map.values()) { 
      Collections.sort(list, c); 
     } 
    } 

    @Override 
    public List<V> getAllValues() { 
     final List<V> result = new ArrayList<V>(); 
     for (List<V> list : map.values()) { 
      result.addAll(list); 
     } 
     return result; 
    } 

    public Collection<List<V>> values(Comparator<? super K> c) { 
     List<Map.Entry<K, List<V>>> entries = new ArrayList<Map.Entry<K, List<V>>>(entrySet()); 

     Collections.sort(entries, new EntryComparator(c)); 

     Collection<List<V>> result = new ArrayList<List<V>>(); 

     for (Map.Entry<K, List<V>> entry : entries) { 
      result.add(entry.getValue()); 
     } 

     return result; 
    } 

    private class EntryComparator implements Comparator<Map.Entry<K, List<V>>>{ 

     private Comparator<? super K> keyComparator = null; 

     private EntryComparator(Comparator<? super K> keyComparator) { 
      this.keyComparator = keyComparator; 
     } 

     @Override 
     public int compare(Map.Entry<K, List<V>> o1, Map.Entry<K, List<V>> o2) { 
      return keyComparator.compare(o1.getKey(), o2.getKey()); 
     } 
    } 

    @Override 
    public void lock() { 
     this.lock = true; 
    } 

    private void checkLock() { 
     if (this.lock) { 
      throw new UnsupportedOperationException(); 
     } 
    } 
} 

的行爲是下一個:

  1. 列表項
  2. 如果您嘗試使用未在地圖中呈現的鍵添加值,然後是新列表元素將被創建並存儲在具有指定鍵的地圖中(值將被添加到當然列表中)
  3. 如果key已經在map中,那麼:if isNeedToCheckUniqueness == false新值只會被添加到列表的末尾(isNeedToCheckUniqueness == true)值將被添加到列表中,以防列表中是否已經包含它。

通過獲取列表大小,您可以通過按鍵(頻率)輕鬆地對元素數進行計數。 您可以獲取列表的第一個或最後一個元素,以獲得指定鍵的第一個或最後一個添加值。

1

番石榴HashMultiset是一個方便的選擇。例如:

HashMultiset<String> multiSet = HashMultiset.create(); 
multiSet.add("a"); 
multiSet.add("a"); 
multiSet.add("b"); 

Assert.assertEquals(2, multiSet.count("a"));//count "a" 
Assert.assertEquals(3, multiSet.size());//set size 
Assert.assertEquals(2, multiSet.elementSet().size());//unique (distinct) size 
+0

可替代地,有在Apache共享類別一個[袋(http://commons.apache.org/collections/api-3.1/org/apache/commons/collections/Bag.html)。 –