一個基本問題的OK位在這裏找到在HashSet中最常見的價值,但我想知道什麼是最好的方式去這...的Java
我有我添加的對象,在HashSet的。如果add()方法不存在,add()方法將只添加一個對象。但我想要做的就是添加所有對象,然後在最後得到下面的結果..
的獨特-Number(不同的)對象
對象-The平均頻率
有人能指出我正確的方向?
在此先感謝
一個基本問題的OK位在這裏找到在HashSet中最常見的價值,但我想知道什麼是最好的方式去這...的Java
我有我添加的對象,在HashSet的。如果add()方法不存在,add()方法將只添加一個對象。但我想要做的就是添加所有對象,然後在最後得到下面的結果..
的獨特-Number(不同的)對象
對象-The平均頻率
有人能指出我正確的方向?
在此先感謝
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
使用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;
}
}
}
您可以只用(哈希)地圖而不是保持計數爲每個不同的對象值在地圖上,或者您可以繼續使用一組,但地方統計所有來電添加。
插入的對象總數是您計算的數量或映射中所有值的總和(迭代EntrySet)。不同對象的數量始終是您的地圖/集的大小()和平均值。頻率明顯是商。
對於這樣的情況下,我用我自己的實現地圖界面:
/*
* 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();
}
}
}
的行爲是下一個:
通過獲取列表大小,您可以通過按鍵(頻率)輕鬆地對元素數進行計數。 您可以獲取列表的第一個或最後一個元素,以獲得指定鍵的第一個或最後一個添加值。
番石榴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
可替代地,有在Apache共享類別一個[袋(http://commons.apache.org/collections/api-3.1/org/apache/commons/collections/Bag.html)。 –
這正是我所追求的...並找到平均值,是否有一個更有效的方法,而不是迭代通過地圖? – DaveB
@DaveB:你真的*需要個人計數嗎?如果是這樣,這絕對是正確的方法。如果不是,我*認爲*我是你的。 –
@DaveB - 此代碼片段輸出單個對象的頻率,而不是[平均值](http://en.wikipedia.org/wiki/Average)。當談到效率時,一個簡單的for循環就是O(n)[複雜類](http://en.wikipedia.org/wiki/Complexity_class),它非常有效。此外,讀取動態地圖的所有條目時不需要進行某種迭代,這是不可能的。 – Saul