这里有一个基本问题,但我想知道最好的方法是什么......
我有一个HashSet,我正在添加对象,.add()方法只会添加一个对象(如果它尚不存在)。但我想要做的是添加所有对象,然后在最后获得以下结果..
- 独特(不同)对象的数量
- 物体的平均频率
有人能指出我正确的方向吗?
提前致谢
答案 0 :(得分:7)
使用HashMap。使用条目作为键,并将它们映射到整数以保持计数。
编辑:你可能想要包装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;
}
}
}
答案 1 :(得分: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
答案 2 :(得分:1)
不同对象的数量只是之后哈希集的大小。
根据“平均频率”的含义,您可以使用source.size() / set.size()
...(如果需要,可以将其中一个操作数强制转换为double
以强制浮点运算)。如果您可以通过一些示例详细说明您的需求,我们可以提供更多帮助。
答案 3 :(得分: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
答案 4 :(得分:0)
您可以只使用(哈希)地图而不是将每个不同对象的计数保留为地图中的值,或者您可以继续使用集合但在某处计算所有要添加的调用。
插入的对象总数是您计算的数量或地图中所有值的总和(迭代EntrySet)。不同对象的数量始终是地图/集的大小()和平均值。频率显然是商。
答案 5 :(得分:0)
对于这种情况,我使用自己的Map接口实现:
/*
* 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();
}
}
}
接下来是行为:
您可以通过获取列表大小轻松按键(频率)计算元素数量。 您可以获取列表的第一个或最后一个元素,以获得具有指定键的第一个或最后一个添加值。