Java-комбинация интерфейсов Set и List - PullRequest
4 голосов
/ 16 октября 2011

У меня есть структура данных, для которой я сейчас использую ArrayList.Я понял, что в этой структуре я не хочу, чтобы присутствовали дубликаты.Моей первой мыслью было использование некоторой формы набора, однако порядок также важен.После небольшого поиска в Google Collections docs я нашел LinkedHashSet, который почти выполняет свою работу.К сожалению, одна из основных причин сохранения порядка заключается в том, что я использую метод get(int index) ArrayList для произвольного доступа, и я не вижу никакого способа обойти это.

Более кратко - мне нуженнабор, который сохраняет порядок и разрешает произвольный доступ.Ни один из классов, на которые я до сих пор смотрел, не предоставляет такую ​​функциональность.Кто-нибудь знает класс, который предлагает это, или я должен буду сделать это сам?Если это последний случай, есть ли какие-либо подводные камни при создании такой структуры, о которой люди знают?

(В качестве альтернативы, будет достаточно быстрого и простого способа поиска и удаления дубликатов из ArrayList или аналогичной структуры)

РЕДАКТИРОВАТЬ: для ясности важен порядок добавления элементов в список, а не их сравнение друг с другом

Ответы [ 4 ]

10 голосов
/ 16 октября 2011

SetUniqueList из общих фондов:

List<Foo> uniqueList = SetUniqueList.decorate(new ArrayList<Foo>());

(к сожалению, коллекции commons по-прежнему не поддерживают дженерики, поэтому здесь вам придется отключить предупреждение)

1 голос
/ 16 октября 2011

Я бы просто продлил ArrayList.

public class SetList<E> extends ArrayList<E> {

    @Override
    public boolean add(E e) {
        return contains(e) ? false : super.add(e);
    }

    @Override
    public void add(int index, E e) {
        if (!contains(e)) {
            super.add(index, e);
        }
    }

    @Override
    public boolean addAll(Collection<? extends E> c) {
        return addAll(size(), c);
    }

    @Override
    public boolean addAll(int index, Collection<? extends E> c) {
        Collection<E> copy = new ArrayList<E>(c);
        copy.removeAll(this);
        return super.addAll(index, copy);
    }

}

Обратите внимание, что метод add() соответствует контракту :

Гарантирует, что эта коллекция содержит указанный элемент (необязательная операция). Возвращает true, если эта коллекция изменилась в результате вызова. (Возвращает false, если эта коллекция не допускает дублирования и уже содержит указанный элемент.)

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

Вы можете использовать ArrayList и HashMap вместе:

import java.util.*;

class AS<T>{

    private HashMap<T, Integer> m = new HashMap<T, Integer>();
    private ArrayList<T> a = new ArrayList<T>();

    public void add(T object){
        if (!m.containsKey(object)){
            m.put(object, a.size());
            a.add(object);
        }
    }
    public void remove(T object){
        Integer i = m.get(object);
        if (i!=null){
            a.remove(i.intValue());
            m.remove(object);
        }
    }
    public void remove(int index){
        m.remove(a.get(index));
        a.remove(index);
    }
    public T get(int index){
        return a.get(index);
    }

    public String toString(){return a.toString();}
}
0 голосов
/ 16 октября 2011

Как насчет создания подкласса AbstractList, который сохраняет ArrayList в качестве своего резервного хранилища, переопределяет большинство методов для делегирования их в резервное хранилище и переопределяет add() для отклонения дубликатов?

class NoDupesList<E> extends AbstractList<E> {
    private final List<E> backing;

    NoDupesList() {
        backing = new ArrayList<E>();
    }

    public E get(int index) {
        return backing.get(index);
    }

    // ...

    public boolean contains(Object o) {
        return backing.contains(o);
    }

    public boolean add(E e) {
        if (contains(e))
            throw new IllegalArgumentException("duplicates disallowed: " + e):

        return backing.add(e);
    }
 }
...