Есть ли там реализация списка без дубликатов?


Я знаю, о SortedSet, но в моем случае мне нужно что-то, что реализует List, а не Set. Так есть ли реализация там, в API или в другом месте?

Это не должно быть трудно реализовать себя, но я подумал, почему бы не спросить людей здесь впервые?

11 77

11 ответов:

в стандартной библиотеке нет коллекции Java для этого. LinkedHashSet<E> сохраняет порядок аналогично a List, хотя, так что если вы обернуть в List когда вы хотите использовать его как List вы получите семантику, которую вы хотите.

кроме того,Викискладе Коллекции (или commons-collections4, для общей версии) имеет List который делает то, что вы уже хотите: SetUniqueList/SetUniqueList<E>.

вот что я сделал и это работает.

предполагая, что у меня есть ArrayList для работы с первым, что я сделал был создан новый LinkedHashMap.

LinkedHashSet<E> hashSet = new LinkedHashSet<E>()

затем я пытаюсь добавить новый элемент LinkedHashSet. Метод add не изменяет LinkedHasSet и возвращает false, если новый элемент является дубликатом. Так что это становится условием, которое я могу проверить перед добавлением в ArrayList.

if (hashSet.add(E)) arrayList.add(E);

это простой и элегантный способ, чтобы предотвратить дубликаты от добавлен в список массивов. Если вы хотите, вы можете инкапсулировать его и переопределить метод add в классе, который расширяет ArrayList. Просто не забудьте разобраться с addAll путем циклического перебора элементов и вызова метода add.

Так вот что я сделал в конце концов. Я надеюсь, что это поможет кому-то еще.

class NoDuplicatesList<E> extends LinkedList<E> {
    @Override
    public boolean add(E e) {
        if (this.contains(e)) {
            return false;
        }
        else {
            return super.add(e);
        }
    }

    @Override
    public boolean addAll(Collection<? extends E> collection) {
        Collection<E> copy = new LinkedList<E>(collection);
        copy.removeAll(this);
        return super.addAll(copy);
    }

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

    @Override
    public void add(int index, E element) {
        if (this.contains(element)) {
            return;
        }
        else {
            super.add(index, element);
        }
    }
}   

вы должны серьезно рассмотреть ответ диллера:

  1. вместо того, чтобы беспокоиться о добавлении ваших объектов в список без дубликатов, добавьте их в набор (любую реализацию), который по своей природе будет отфильтровывать дубликаты.
  2. когда вам нужно вызвать метод, который требует список, оберните его в new ArrayList(set) (или new LinkedList(set) и т. д.).

Я думаю, что решение вы разместили с NoDuplicatesList есть некоторые проблемы, в основном с contains() способ, кроме того, ваш класс не обрабатывает проверку на наличие дубликатов в коллекции, переданной вашему addAll() метод.

почему бы не инкапсулировать набор со списком, например:

new ArrayList( new LinkedHashSet() )

Это оставляет другую реализацию для кого-то, кто является настоящим мастером коллекций; -)

Мне нужно было что-то вроде этого, поэтому я пошел в коллекции commons и использовал SetUniqueList, но когда я запустил какой-то тест производительности, я обнаружил, что он кажется не оптимизированным по сравнению с тем, если я хочу использовать набор и получить массив с помощью набора.метод toArray (), SetUniqueTest занял 20: 1 время, чтобы заполнить, а затем пересечь 100 000 строк по сравнению с другой реализацией, что является большой разницей, поэтому, если вы беспокоитесь о производительности, я рекомендую вам использовать набор и получить массив вместо использования SetUniqueList, если вам действительно не нужна логика SetUniqueList, то вам нужно проверить другие решения...

основной метод тестирования кода:

public static void main (String[] args) {

SetUniqueList pq = SetUniqueList.decorate(new ArrayList());
Set s = new TreeSet();

long t1 = 0L;
long t2 = 0L;
String t;


t1 = System.nanoTime();
for (int i = 0; i < 200000; i++) {
    pq.add("a" + Math.random());
}
while (!pq.isEmpty()) {
    t = (String) pq.remove(0);
}
t1 = System.nanoTime() - t1;

t2 = System.nanoTime();
for (int i = 0; i < 200000; i++) {
    s.add("a" + Math.random());
}

s.clear();
String[] d = (String[]) s.toArray(new String[0]);
s.clear();
for (int i = 0; i < d.length; i++) {
    t = d[i];

}
t2 = System.nanoTime() - t2;

System.out.println((double)t1/1000/1000/1000); //seconds
System.out.println((double)t2/1000/1000/1000); //seconds
System.out.println(((double) t1) / t2);        //comparing results

}

С уважением Мохаммед Слим http://abusleem.net/blog

Примечание: он не принимает подсписок реализация во внимание.

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

public class UniqueList<T> extends ArrayList<T> {

    private static final long serialVersionUID = 1L;

    /** Unique elements SET */
    private final Set<T> set=new HashSet();

    /** Used by addAll methods */
    private Collection<T> addUnique(Collection<? extends T> col) {
        Collection<T> unique=new ArrayList();
        for(T e: col){
            if (set.add(e)) unique.add(e);
        }
        return unique;
    }

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

    @Override
    public boolean addAll(Collection<? extends T> col) {
        return super.addAll(addUnique(col));
    }

    @Override
    public void add(int index, T e) {
        if (set.add(e)) super.add(index, e);
    }

    @Override
    public boolean addAll(int index, Collection<? extends T> col) {
        return super.addAll(index, addUnique(col));
    }

}

The документация для интерфейсов сбора говорит:

Set-коллекция, которая не может содержать повторяющиеся элементы.
Список-упорядоченная коллекция (иногда называемая последовательностью). Списки могут содержать повторяющиеся элементы.

Так что если вы не хотите дубликатов, вы, вероятно, не должны использовать список.

на add способ, почему бы не использовать HashSet.add() чтобы проверить дубликаты вместо HashSet.consist(). HashSet.add() вернутся true если нет дубликатов и false в противном случае.

С верхней части моей головы, списки разрешить дубликаты. Вы можете быстро реализовать UniqueArrayList и переопределить все add/insert функции для проверки contains() перед вызовом унаследованных методов. Для личного использования вы можете реализовать только add метод, который вы используете, и переопределить другие, чтобы бросить исключение в случае, если будущие программисты пытаются использовать список по-другому.

Я только что сделал свой собственный уникальный список в моей собственной маленькой библиотеке, как это:

package com.bprog.collections;//my own little set of useful utilities and classes

import java.util.HashSet;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author Jonathan
*/
public class UniqueList {

private HashSet masterSet = new HashSet();
private ArrayList growableUniques;
private Object[] returnable;

public UniqueList() {
    growableUniques = new ArrayList();
}

public UniqueList(int size) {
    growableUniques = new ArrayList(size);
}

public void add(Object thing) {
    if (!masterSet.contains(thing)) {
        masterSet.add(thing);
        growableUniques.add(thing);
    }
}

/**
 * Casts to an ArrayList of unique values
 * @return 
 */
public List getList(){
    return growableUniques;
}

public Object get(int index) {
    return growableUniques.get(index);
}

public Object[] toObjectArray() {
    int size = growableUniques.size();
    returnable = new Object[size];
    for (int i = 0; i < size; i++) {
        returnable[i] = growableUniques.get(i);
    }
    return returnable;
    }
}

у меня есть класс TestCollections, который выглядит так:

package com.bprog.collections;
import com.bprog.out.Out;
/**
*
* @author Jonathan
*/
public class TestCollections {
    public static void main(String[] args){
        UniqueList ul = new UniqueList();
        ul.add("Test");
        ul.add("Test");
        ul.add("Not a copy");
        ul.add("Test"); 
        //should only contain two things
        Object[] content = ul.toObjectArray();
        Out.pl("Array Content",content);
    }
}

работает нормально. Все, что он делает, это добавляет к набору, если у него его еще нет, и есть ArrayList, который можно вернуть, а также массив объектов.