Skip to content

Instantly share code, notes, and snippets.

@bemusementpark
Last active May 27, 2016 17:55
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bemusementpark/80730eaafdfe816ddbb1 to your computer and use it in GitHub Desktop.
Save bemusementpark/80730eaafdfe816ddbb1 to your computer and use it in GitHub Desktop.
A List that prevents duplicates with O(1) random access. Similar to a LinkedHashSet but more useful in an Adapter class thanks to O(1) random access.
import android.support.annotation.NonNull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.RandomAccess;
import java.util.Set;
/**
* Created by andy on 14/08/15.
*/
public class UniqueList<T> extends ArrayList<T> implements List<T> , Set<T> , RandomAccess
{
HashMap<T,Integer> hash; // T -> int
public UniqueList()
{
hash = new HashMap<>();
}
/*
* O(n)
* */
@Override
public void add(int location, T object)
{
super.add(location, object);
for( int i = location ; i < size() ; i++ )
{
hash.put(get(i),i);
}
}
/*
* O(1) amortized.
* */
@Override
public boolean add(T object) {
if( hash.containsKey(object) ) return false;
hash.put(object, size());
super.add(object);
return true;
}
/*
* O(MAX(collection.size(),n)) because of the hash-value-shift afterwards.
* */
@Override
public boolean addAll(int location, Collection<? extends T> collection) {
boolean bChanged = false;
for( T t : collection)
{
if( ! hash.containsKey( t ) )
{
hash.put(t, size());
super.add(t);
bChanged = true;
}
}
for( int i = location + collection.size() ; i < size() ; i ++ )
{
hash.put( get(i) , i );
}
return bChanged;
}
/*
* O(collection.size())
* */
@Override
public boolean addAll(Collection<? extends T> collection) {
boolean bChanged = false;
for( T t : collection)
{
if( ! hash.containsKey( t ) )
{
hash.put( t , size() );
super.add(t);
bChanged = true;
}
}
return bChanged;
}
/*
* O(n)
* */
@Override
public void clear() {
hash.clear();
super.clear();
}
/*
* O(1)
* */
@Override
public boolean contains(Object object) {
return hash.containsKey(object);
}
/*
* O(collection.size())
* */
@Override
public boolean containsAll(Collection<?> collection) {
boolean bContainsAll = true;
for( Object c : collection ) bContainsAll &= hash.containsKey(c);
return bContainsAll;
}
/*
* O(1)
* */
@Override
public int indexOf(Object object) {
//noinspection SuspiciousMethodCalls
Integer index = hash.get(object);
return index!=null?index:-1;
}
/*
* O(1)
* */
@Override
public int lastIndexOf(Object object)
{
return hash.get(object);
}
/*
* O(n) because of the ArrayList.remove and hash adjustment
* */
@Override
public T remove(int location) {
T t = super.remove(location);
hash.remove( t );
for( int i = size() - 1 ; i >= location ; i -- )
{
hash.put( get(i) , i );
}
return t;
}
/*
* O(n) because of the ArrayList.remove and hash adjustment
* */
@Override
public boolean remove(Object object) {
Integer i = hash.get( object );
if( i == null ) return false;
remove( i.intValue() );
return true;
}
/*
* O( MAX( collection.size() , ArrayList.removeAll(collection) ) )
* */
@Override
public boolean removeAll(@NonNull Collection<?> collection) {
for( Object c : collection )
{
hash.remove( c );
}
return super.removeAll( collection );
}
}
@Winghin2517
Copy link

Hi. Do I have to override the hashCode and equals methods in the object in which I use this class?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment