The trick here is to use Collections.shuffle(List list):
List<Integer> list = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20);
Collections.shuffle(list);
System.out.println(list);
The progressive version goes something like this:
// Wrap it in an ArrayList so I can modify it.
List<Integer> list = new ArrayList(Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20));
for (int i = 21; i < 25; i++) {
System.out.println(list);
// Shuffle it.
Collections.shuffle(list);
// Grab one.
Integer take = list.get(0);
list.remove(take);
System.out.println("Took " + take);
// Add my new candidate.
list.add(i);
}
Or you could go the whole hog and make it an Iterable
:
public static class CreepingRandom implements Iterable<Integer> {
// The starting list.
private final List<Integer> start;
// How many steps to add.
private final int steps;
// What int to start adding.
private final int from;
public CreepingRandom(int initialSize, int from, int steps) {
// Make my start list.
start = new ArrayList<Integer>(initialSize);
// Fill it.
for (int i = 1; i <= initialSize; i++) {
start.add(i);
}
// Remember where to start from.
this.from = from;
// Remember how many steps.
this.steps = steps;
}
@Override
public Iterator<Integer> iterator() {
return new CreepingIterator();
}
private class CreepingIterator implements Iterator<Integer> {
// Track how many I've delivered.
int delivered = 0;
// The next number to add.
int add = from;
// My current list.
final ArrayList<Integer> list = new ArrayList(start);
@Override
public boolean hasNext() {
return delivered < steps;
}
@Override
public Integer next() {
// Shuffle it.
Collections.shuffle(list);
// Pull one out.
Integer next = list.get(0);
// Add my new one in.
list.set(0, add++);
// Count them.
delivered += 1;
return next;
}
}
}
public void test() {
for (Integer i : new CreepingRandom(20, 21, 100)) {
System.out.println(i);
}
}
private class CreepingIterator implements Iterator<Integer> {
// Track how many I've delivered.
int delivered = 0;
// The next number to add.
int add = from;
// My current list.
final ArrayList<Integer> list;
CreepingIterator() {
// Copy the start list - Use LinkedList for efficiency of add and removeFirst.
list = new ArrayList(start);
}
@Override
public boolean hasNext() {
return delivered < steps;
}
@Override
public Integer next() {
// Shuffle it.
Collections.shuffle(list);
// Pull one out.
Integer next = list.get(0);
// Add my new one in.
list.set(0, add++);
// Count them.
delivered += 1;
return next;
}
}
}
public void test() {
for (Integer i : new CreepingRandom(20, 21, 100)) {
System.out.println(i);
}
}