Есть ли реализация List без дубликатов? - PullRequest
79 голосов
/ 06 ноября 2008

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

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

Ответы [ 11 ]

84 голосов
/ 06 ноября 2008

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

В качестве альтернативы, Commons Collections (или commons-collections4 для универсальной версии) имеет List, который делает то, что вы уже хотите: SetUniqueList / SetUniqueList<E>.

11 голосов
/ 24 апреля 2014

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

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

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

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

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

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

10 голосов
/ 06 ноября 2008

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

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);
        }
    }
}   
4 голосов
/ 06 ноября 2008

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

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

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

4 голосов
/ 06 ноября 2008

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

new ArrayList( new LinkedHashSet() )

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

3 голосов
/ 22 июля 2009

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

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

public static void main (аргументы String []) {

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

1 голос
/ 04 марта 2016

ПРИМЕЧАНИЕ: не учитывается реализация subList .

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));
    }

}
0 голосов
/ 13 января 2012

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

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

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

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, который можно вернуть, а также массив объектов.

0 голосов
/ 06 ноября 2008

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

...