¿Existe un conjunto de preservación de orden de inserción que también implemente List?

85

Estoy tratando de encontrar una implementación de java.util.Listy java.util.Setal mismo tiempo en Java. Quiero que esta clase permita solo elementos únicos (como Set) y preserve su orden (como List). ¿Existe en JDK 6?

Es importante tenerlo List<T>#add(int, T)para poder insertarlo en una posición específica.

yegor256
fuente
¿Te refieres a conservar su orden de inserción o algún orden definido por un Comparator? ¿También quieres la semántica de la Listinterfaz?

Respuestas:

207

TreeSetestá ordenado por orden de elementos; LinkedHashSetconserva la orden de inserción. Con suerte, uno de esos es lo que buscabas.

Ha especificado que desea poder insertar en una ubicación arbitraria , sospecho que tendrá que escribir la suya propia, simplemente cree una clase que contenga una HashSet<T>y una ArrayList<T>; al agregar un elemento, verifique si está o no en el conjunto antes de agregarlo a la lista.

Alternativamente, las ofertas commons-collections4 de Apache ListOrderedSety SetUniqueList, que se comportan de manera similar y deben cumplir con los requisitos dados.

Jon Skeet
fuente
12

¿Quieres decir como LinkedHashSet? Esto conserva el orden de entrada, pero no permite duplicados.

En mi humilde opinión, es un requisito inusual, pero puede escribir una lista sin duplicados.

class SetList<T> extends ArrayList<T> {
    @Override
    public boolean add(T t) {
        return !super.contains(t) && super.add(t);
    }

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

    @Override
    public boolean addAll(Collection<? extends T> c) {
        boolean added = false;
        for (T t : c)
            added |= add(t);
        return added;
    }

    @Override
    public boolean addAll(int index, Collection<? extends T> c) {
        boolean added = false;
        for (T t : c)
            if (!super.contains(t)) {
                super.add(index++, t);
                added = true;
            }
        return added;
    }
}
Peter Lawrey
fuente
No implementa la Listinterfaz, vea mis cambios a la pregunta
yegor256
2
stackoverflow.com/a/8185105/253468 se ve mejor porque no tiene O(n)complejidad de inserción, hay una compensación que se debe considerar entre el almacenamiento doble y la O(log(n))operación de inserción.
TWiStErRob
8

No se puede implementar Listy Setde inmediato sin violación del contrato. Ver, por ejemplo, el Set.hashCodecontrato:

El código hash de un conjunto se define como la suma de los códigos hash de los elementos del conjunto, donde el código hash de un elemento nulo se define como cero.

Por otro lado, aquí está el contrato de List.hashCode:

El código hash de una lista se define como el resultado del siguiente cálculo:

int hashCode = 1;
for (E e : list)
    hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());

Por lo tanto, es imposible implementar una clase única que garantice el cumplimiento de ambos contratos. El mismo problema de equalsimplementación.

Tagir Valeev
fuente
4

Si no se limita a JDK 6, puede usar la biblioteca de colecciones comunes de Apache, que ofrece una correspondencia exacta para sus necesidades: ListOrderedSet . Es como Listy Setcombinado juntos :)

Ondrej Bozek
fuente
menos la Listinterfaz
LateralFractal
0

Tuve un problema similar, así que escribí el mío. Vea aquí . Se IndexedArraySetextiende ArrayListe implementa Set, por lo que debe admitir todas las operaciones que necesita. Tenga en cuenta que insertar elementos en ubicaciones en el medio de una ArrayListpuede ser lento para listas grandes porque es necesario mover todos los elementos siguientes. Mi IndexedArraySetno cambia eso.

JanKanis
fuente
0

Otra opción (menos el Listrequisito de interfaz) es la de Guava ImmutableSet, que conserva el orden de inserción. Desde su página wiki :

A excepción de las colecciones ordenadas, el orden se conserva desde el momento de la construcción. Por ejemplo,

ImmutableSet.of("a", "b", "c", "a", "d", "b")

iterará sobre sus elementos en el orden "a", "b", "c", "d".

kuporífico
fuente