package edu.northwestern.at.utils; /* Please see the license information at the end of this file. */ import java.util.*; /** Sorted array list. * * <p> * This class extends ArrayList to support sorted lists. * </p> * * <p> * All elements of the list should implement the Comparable interface, * or you may supply a custom Comparator instead. If the objects do not * support comparable and you do not supply a custom Comparator, the * result of the toString() function for each object is used. * </p> * * <p> * The ArrayList methods for adding or settings elements at specific indices * are not supported raise an UnsupportedOperationException if used. * </p> */ public class SortedArrayList<E> extends ArrayList<E> { /** Optional Comparator used for comparing objects in the list. */ protected Comparator<E> comparator = null; /** Create empty sorted array list. */ public SortedArrayList() { super(); } /** Create empty sorted array list with specified initial capacity. */ public SortedArrayList( int initialCapacity ) { super( initialCapacity ); } /** Create sorted array list from a collection. * * @param collection The source collection. */ public SortedArrayList( Collection<? extends E> collection ) { // Create empty list. super(); addAll( collection ); } /** Create sorted array list from an array. * * @param array The source array. */ public SortedArrayList( E[] array ) { // Create empty list. super(); addAll( Arrays.asList( array ) ); } /** Create empty sorted array list with specified Comparator. */ public SortedArrayList( Comparator<E> comparator ) { super(); this.comparator = comparator; } /** Create sorted array list from a collection with specified comparator. * * @param collection The source collection. * @param comparator The comparator. */ public SortedArrayList ( Collection<? extends E> collection , Comparator<E> comparator ) { // Create empty list. super(); // Set comparator. this.comparator = comparator; // Add all elements from collection. addAll( collection ); } /** Create sorted array list from an array with specified comparator. * * @param array The source array. * @param comparator The comparator. */ public SortedArrayList( E[] array , Comparator<E> comparator ) { // Create empty list. super(); // Set comparator. this.comparator = comparator; // Add all elements from array. addAll( array ); } /** Create empty sorted array list with specified initial capacity * and comparator. */ public SortedArrayList( int initialCapacity , Comparator<E> comparator ) { super( initialCapacity ); this.comparator = comparator; } /** Set comparator for list elements. * * @param comparator The comparator. */ public void setComparator( Comparator<E> comparator ) { this.comparator = comparator; } /** Add an object to the list. * * @param object Object to add. * * @return True if object added. */ public boolean add( E object ) { // Don't allow adding null objects. if ( object == null ) return false; // Binary search to find insertion point. int i = 0; int j = size() - 1; while ( i <= j ) { int k = ( i + j ) / 2; int c = compare( object , get( k ) ); if ( c < 0 ) { j = k - 1; } else if ( c > 0 ) { i = k + 1; } else { i = k; break; } } // Add object at correct position in list. super.add( i , object ); return true; } /** Add element at specified index. Not allowed. */ public void add( int index , E object ) { throw new UnsupportedOperationException(); } /** Add all elements of a collection. * * @param collection The source collection. * * @return True if all objects added, false otherwise. */ public boolean addAll( Collection<? extends E> collection ) { boolean result = false; if ( collection != null ) { super.addAll( collection ); sort(); result = true; } return result; } /** Add all elements of an array. * * @param array The source array. * * @return True if all objects added, false otherwise. */ public boolean addAll( E[] array ) { boolean result = false; if ( array != null ) { super.addAll( Arrays.asList( array ) ); sort(); result = true; } return result; } /** Add all elements of a collection at a specified index. Not allowed. */ public boolean addAll ( int index , Collection<? extends E> collection ) { throw new UnsupportedOperationException(); } /** Determine if list contains a specified value. * * @param object The object (value) to find. * * @return true if the list contains specified object, * false otherwise. */ public boolean contains( Object object ) { return ( indexOf( object ) >= 0 ); } /** Return index of first matching list entry. * * @param object The object to find. * * @return Index of the first matching object, if any. * Returns -1 if no matching object is found. */ public int indexOf( Object object ) { int result = -1; // Null object returns -1. if ( object == null ) return result; // Binary search to find matching object. int i = 0; int j = size() - 1; while ( i <= j ) { int k = ( i + j ) / 2; int c = compare( object , get( k ) ); if ( c < 0 ) { j = k - 1; } else if ( c > 0 ) { i = k + 1; } else { // We found a matching object. // Walk backwards through the array list // to make sure it is the first one. result = k; int l = k - 1; while ( ( l >= 0 ) && ( compare( object , get( l ) ) == 0 ) ) l--; if ( ( l + 1 ) < result ) result = l + 1; break; } } return result; } /** Return index of last matching list entry. * * @param object The object to find. * * @return Index of the last matching object, if any. * Returns -1 if no matching object is found. */ public int lastIndexOf( Object object ) { int result = -1; // Null object returns -1. if ( object == null ) return result; // Binary search to find matching object. int i = 0; int j = size() - 1; while ( i <= j ) { int k = ( i + j ) / 2; int c = compare( object , get( k ) ); if ( c < 0 ) { j = k - 1; } else if ( c > 0 ) { i = k + 1; } else { // We found a matching object. // Walk forwards through the array list // to find the last matching object. result = k; int l = k + 1; while ( ( l < size() ) && ( compare( object , get( l ) ) == 0 ) ) l++; if ( ( l - 1 ) > result ) result = l - 1; break; } } return result; } /** Set specified element of list. Not allowed. */ public E set( int index , E object ) { throw new UnsupportedOperationException(); } /** Compares two elements. * * @param object1 First object. * @param object2 Second object. * * @return Result of comparison. * * <p> * Assumes the two objects are not null, since null objects cannot * added to the list. If no comparator is defined for this * SortedArrayList, and one or both of the objects are not comparable, * a case-ignoring comparison is performed on the "toString()" values * for each object. * </p> */ @SuppressWarnings("unchecked") protected int compare( Object object1 , Object object2 ) { if ( comparator != null ) { return comparator.compare( (E)object1 , (E)object2 ); } else if ( ( object1 instanceof Comparable ) && ( object2 instanceof Comparable ) ) { return ( (Comparable)object1 ).compareTo( (Comparable)object2 ); } else { String s1 = null; String s2 = null; if ( object1 != null ) s1 = object1.toString(); if ( object2 != null ) s2 = object2.toString(); return StringUtils.compareIgnoreCase( s1 , s2 ); } } /** Sort list. */ @SuppressWarnings("unchecked") protected void sort() { // Copy list to array. E[] eArray = (E[])toArray(); // Clear current list. clear(); // Sort array. Arrays.sort( eArray ); // Get enough space for list to hold // sorted array elements. ensureCapacity( eArray.length ); // Copy array to list. for ( int i = 0 ; i < eArray.length ; i++ ) { super.add( eArray[ i ] ); } } } /* Copyright (c) 2008, 2009 by Northwestern University. All rights reserved. Developed by: Academic and Research Technologies Northwestern University http://www.it.northwestern.edu/about/departments/at/ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal with the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimers. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimers in the documentation and/or other materials provided with the distribution. * Neither the names of Academic and Research Technologies, Northwestern University, nor the names of its contributors may be used to endorse or promote products derived from this Software without specific prior written permission. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. */