Знаю SortedSet
, но в моем случае мне нужно то, что реализует List
, а нет Set
. Так есть ли там реализация, в API или где-то еще?
Это не должно быть сложно реализовать, но я подумал, почему бы сначала не спросить здесь людей?
java
list
collections
duplicates
Юваль
источник
источник
Ответы:
Для этого в стандартной библиотеке нет коллекции Java. однако
LinkedHashSet<E>
сохраняет порядок, аналогично aList
, поэтому, если вы оберните свой набор в a,List
когда вы хотите использовать его как a,List
вы получите желаемую семантику.В качестве альтернативы, Коллекции Commons (или
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
циклом по элементам и вызывать метод добавления.источник
Итак, вот что я в итоге сделал. Надеюсь, это поможет кому-то другому.
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); } } }
источник
Почему бы не инкапсулировать набор списком, например:
new ArrayList( new LinkedHashSet() )
Остается другая реализация для тех, кто является настоящим мастером коллекций ;-)
источник
Вам следует серьезно обдумать ответ Дхиллера:
new ArrayList(set)
(или вnew LinkedList(set)
любой другой).Я думаю, что решение, которое вы опубликовали с помощью,
NoDuplicatesList
имеет некоторые проблемы, в основном сcontains()
методом, плюс ваш класс не обрабатывает проверку дубликатов в коллекции, переданной вашемуaddAll()
методу.источник
Мне нужно было что-то подобное, поэтому я пошел в общие коллекции и использовал
SetUniqueList
, но когда я провел некоторый тест производительности, я обнаружил, что он не оптимизирован по сравнению со случаем, если я хочу использоватьSet
и получить сArray
помощьюSet.toArray()
метода.Для заполнения и последующего прохождения 100000 строк
SetUniqueTest
потребовалось 20: 1 времени по сравнению с другой реализацией, что является большой разницей.Итак, если вы беспокоитесь о производительности, я рекомендую вам использовать Set и Get a Array вместо использования
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
}
С уважением, Мохаммед Слим
источник
ПРИМЕЧАНИЕ: он не принимает во внимание реализацию подсписка .
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)); } }
источник
В документации для интерфейсов сбора говорится:
Поэтому, если вам не нужны дубликаты, вам, вероятно, не следует использовать список.
источник
in
add
, почему бы не использоватьHashSet.add()
для проверки дубликатов вместоHashSet.consist()
.HashSet.add()
вернется,true
если нет дубликатов и вfalse
противном случае.источник
HashSet#consist()
?Вне моей головы списки допускают дублирование. Вы можете быстро реализовать
UniqueArrayList
и переопределить все функцииadd
/insert
для проверкиcontains()
перед вызовом унаследованных методов. Для личного использования вы можете реализовать только тотadd
метод, который используете, и переопределить другие, чтобы генерировать исключение на случай, если будущие программисты попытаются использовать список по-другому.источник
Я только что создал свой собственный список UniqueList в своей небольшой библиотеке, вот так:
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, а также массив объектов.
источник