Java найти наиболее распространенное значение в HashSet - PullRequest
0 голосов
/ 04 октября 2011

Хорошо, немного базового вопроса, но я хотел знать, как лучше это сделать ...

У меня есть HashSet, к которому я добавляю объекты, метод .add ()добавить объект только в том случае, если его еще нет.Но то, что я хочу сделать, это добавить ВСЕ объекты, а в конце получить следующие результаты ..

-Количество уникальных (различных) объектов-Средняя частота объектов

Может ли кто-нибудь указать мне правильное направление?

Заранее спасибо

Ответы [ 6 ]

7 голосов
/ 04 октября 2011

Используйте 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;
        }
    }
}
2 голосов
/ 04 октября 2011

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
1 голос
/ 04 октября 2011

Гуава 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 
1 голос
/ 04 октября 2011

Количество отдельных объектов будет просто размером хэша, установленного впоследствии.

В зависимости от того, что вы подразумеваете под "средней частотой", вы можете использовать source.size() / set.size() ... (возможно, приведение одного из операндов к double для принудительной арифметики с плавающей запятой, если хотите). Если вы можете уточнить, что вам нужно, с некоторыми примерами, мы сможем помочь больше.

0 голосов
/ 04 октября 2011

Для этого случая я использую собственную реализацию интерфейса 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();
        }
    }
}

Поведение следующее:

  1. Элемент списка
  2. Если вы попытаетесь добавить значение с ключом, не представленным на карте, то будет создан новый элемент списка и сохранен на карте с указанным ключом (значение будет добавлено в список курса)
  3. Если ключ уже есть в карте, то: if isNeedToCheckUniqueness == false новое значение просто будет добавлено в конец списка, в противном случае (isNeedToCheckUniqueness == true) значение будет добавлено в список только в том случае, если список еще не содержит его.

Вы можете легко посчитать количество элементов по ключу (частоте), получив размер списка.Вы можете получить первый или последний элемент списка, чтобы получить первое или последнее добавленное значение с указанным ключом.

0 голосов
/ 04 октября 2011

Вы можете либо просто использовать (хэш) карту, чтобы сохранить счет для каждого отдельного объекта в качестве значения на карте, либо вы можете продолжать использовать набор, но где-то посчитать все вызовы для добавления.

общее количество вставленных объектов - это то, что вы посчитали, или сумма по всем значениям на карте (итерируйте по EntrySet).Количество различных объектов всегда является size () вашей карты / набора и средним значением.частота, очевидно, является частным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...