Я знаю про SortedSet
, але в моєму випадку мені потрібно щось, що реалізує List
, і ні Set
. То чи є там реалізація, в API чи деінде?
Це не повинно бути важко реалізувати себе, але я зрозумів, чому б не спершу запитати людей тут?
Я знаю про SortedSet
, але в моєму випадку мені потрібно щось, що реалізує List
, і ні Set
. То чи є там реалізація, в API чи деінде?
Це не повинно бути важко реалізувати себе, але я зрозумів, чому б не спершу запитати людей тут?
Відповіді:
У стандартній бібліотеці для цього немає колекції Java. LinkedHashSet<E>
зберігає порядок подібно до List
, однак, якщо ви обернете свій набір у, List
коли ви хочете використовувати його в якості, 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
, переглядаючи елементи та викликаючи метод 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);
}
}
}
Чому б не інкапсулювати набір зі списком, сортуючи так:
new ArrayList( new LinkedHashSet() )
Це залишає іншу реалізацію для тих, хто є справжнім майстром колекцій ;-)
Вам слід серйозно розглянути відповідь Дхіллера:
new ArrayList(set)
(або a new LinkedList(set)
, що завгодно).Я думаю, що рішення, яке ви опублікували з, NoDuplicatesList
має деякі проблеми, в основному з contains()
методом, плюс ваш клас не обробляє перевірку на наявність дублікатів у колекції, переданій вашому addAll()
методу.
Мені потрібно було щось подібне, тому я пішов до колекцій спільних книг і використав файлSetUniqueList
, але, провівши певний тест продуктивності, я виявив, що це, здається, не оптимізовано порівняно з випадком, якщо я хочу використовувати a Set
та отримати метод Array
використання Set.toArray()
.
Потрібно SetUniqueTest
було 20: 1 заповнити, а потім пройти 100 000 рядків порівняно з іншою реалізацією, що є великою різницею.
Отже, якщо ви турбуєтесь про продуктивність, я рекомендую вам використовувати Set та Get 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));
}
}
У документації для інтерфейсів колекції сказано:
Набір - колекція, яка не може містити повторюваних елементів.
Список - упорядкована колекція (іноді її називають послідовністю). Списки можуть містити повторювані елементи.
Тож якщо ви не хочете дублікатів, вам, мабуть, не слід використовувати список.
в 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, а також масив об’єктів.