/* This code is part of Freenet. It is distributed under the GNU General
* Public License, version 2 (or at your option any later version). See
* http://www.gnu.org/ for further details of the GPL. */
package freenet.support;
import java.util.List;
import java.util.Random;
public class ListUtils {
/**
* Removes element from List by swapping with last element.
* O(n) comparison, O(1) moves.
* This method is useful with ArrayList-alike containers
* with O(1) get(index) and O(n) remove(index)
* when keeping array order is not important.
* Not synchronized (even with synchronized containers).
* @return {@code true} if element was removed.
*/
public static <E> boolean removeBySwapLast(List<E> a, Object o) {
int idx = a.indexOf(o);
if (idx == -1)
return false;
removeBySwapLast(a, idx);
return true;
}
/**
* Removes element by index from List by swapping with last element.
* 0 comparison, O(1) moves.
* This method is useful with ArrayList-alike containers
* with O(1) get(index) and O(n) remove(index)
* when keeping array order is not important.
* Not synchronized (even with synchronized containers!).
* @return moved element that will replace current index or
* removed element if it was last element (and nothing was moved).
* WARNING: returned result is DIFFERENT from List.remove(index)!
* (this is intentional to allow useful optimizations).
* @throws IndexOutOfBoundsException if idx is not valid index
* WARNING: Don't dare to break this method contract!
*/
public static <E> E removeBySwapLast(List<E> a, int idx) {
int size = a.size();
if (idx < 0 || idx >= size) throw new IndexOutOfBoundsException(idx+" out of range [0;"+size+")");
E moved = a.remove(size-1);
if (idx != size-1)
a.set(idx, moved);
return moved;
}
public static class RandomRemoveResult<E> {
public final E removed;
public final E moved;
RandomRemoveResult(E removed, E moved) {
this.removed = removed;
this.moved = moved;
}
}
/**
* Removes random element from List by swapping with last element.
* O(1) moves.
* This method is useful with ArrayList-alike containers
* with O(1) get(index) and O(n) remove(index)
* when keeping array order is not important.
* Not synchronized (even with synchronized containers!).
* WARNING: amount of fetched random data is implementation-defined
* @return null if list is empty, otherwise RandomRemoveResult(removed_element, moved_element)
*/
public static <E> RandomRemoveResult<E> removeRandomBySwapLast(Random random, List<E> a) {
int size = a.size();
if (size == 0) return null;
if (size == 1) {
// short-circuit, avoid expensive random call
E removed = a.remove(0);
return new RandomRemoveResult<E>(removed, removed);
}
int idx = random.nextInt(size);
E removed = a.get(idx);
return new RandomRemoveResult<E>(removed, removeBySwapLast(a, idx));
}
/**
* Removes random element from List by swapping with last element.
* O(1) moves.
* This method is useful with ArrayList-alike containers
* with O(1) get(index) and O(n) remove(index)
* when keeping array order is not important.
* Not synchronized (even with synchronized containers!).
* WARNING: amount of fetched random data is implementation-defined
* @return null if list is empty, removed element otherwise
*/
public static <E> E removeRandomBySwapLastSimple(Random random, List<E> a) {
int size = a.size();
if (size == 0) return null;
if (size == 1) {
// short-circuit, avoid expensive random call
return a.remove(0);
}
int idx = random.nextInt(size);
E removed = a.get(idx);
removeBySwapLast(a, idx);
return removed;
}
}