随机迭代Java中的ArrayList

似乎是一个非常基本的问题。 我有一个ArrayList al ,我想迭代它。 一般,

 for(int i : al) { // some code } 

诀窍。 但我的要求是不是按顺序迭代而是随机迭代。

您可以在列表中使用Collections.shuffle()

请注意,这将使列表本身洗牌,因此如果订单很重要,您应该复制它(并随机播放副本)。

 List newList = new ArrayList<>( oldList ) ; Collections.shuffle( newList ) ; 

或者,您可以创建一个随机数组,其中包含元素0 - List.size()-1并使用它们作为索引来访问List中的“random”元素。

使用以下类:

 import java.util.Enumeration; import java.util.Random; public class RandomPermuteIterator implements Enumeration { int c = 1013904223, a = 1664525; long seed, N, m, next; boolean hasNext = true; public RandomPermuteIterator(long N) throws Exception { if (N <= 0 || N > Math.pow(2, 62)) throw new Exception("Unsupported size: " + N); this.N = N; m = (long) Math.pow(2, Math.ceil(Math.log(N) / Math.log(2))); next = seed = new Random().nextInt((int) Math.min(N, Integer.MAX_VALUE)); } public static void main(String[] args) throws Exception { RandomPermuteIterator r = new RandomPermuteIterator(100); while (r.hasMoreElements()) System.out.print(r.nextElement() + " "); //output:50 52 3 6 45 40 26 49 92 11 80 2 4 19 86 61 65 44 27 62 5 32 82 9 84 35 38 77 72 7 ... } @Override public boolean hasMoreElements() { return hasNext; } @Override public Long nextElement() { next = (a * next + c) % m; while (next >= N) next = (a * next + c) % m; if (next == seed) hasNext = false; return next; } } 

这种方式怎么样(function更强); 它甚至包括一个main()来演示。 基本上,在列表大小范围内生成随机数,直到您拥有其中一个。 我们使用HashSet来处理我们范围内的重复随机数。 然后,将迭代委托给索引hashset的迭代器。 “hasNext()”的逻辑通过委托变得微不足道。

 public class RandomIterator implements Iterator { private Iterator indicies; List delegate; public static void main(String[] args) { Random r = new Random(); List numbers = IntStream.generate(r::nextInt).limit(10).boxed().collect(toCollection(ArrayList::new)); List results = new ArrayList<>(); for(RandomIterator test = new RandomIterator<>(numbers); test.hasNext(); ) { results.add(test.next()); } System.out.println("In list: " + numbers); System.out.println("random iteration " + results); if(results.containsAll(numbers) && results.size() == numbers.size()) System.out.println("Everything accounted for"); else System.out.println("Something broke!"); } public RandomIterator(List delegate) { Random r = new Random(); this.delegate = delegate; Set indexSet = new LinkedHashSet<>(); while(indexSet.size() != delegate.size()) indexSet.add(r.nextInt(delegate.size())); System.out.println(indexSet); indicies = indexSet.iterator(); } @Override public boolean hasNext() { return indicies.hasNext(); } @Override public T next() { return delegate.get(indicies.next()); } } 

如果您只想要打印100个随机数:

  IntStream.generate(r::nextInt).limit(100).forEach(System.out::println); 

如果你想要一个迭代器(无论出于何种原因:)

 IntStream.generate(r::nextInt).limit(100).boxed().collect(Collectors.toList()).iterator(); 
 public class RandomIterator implements Iterator { private static final SecureRandom RANDOM = new SecureRandom(); private final int[] order; private final List elements; public RandomIterator(List elements) { this.elements = elements; this.order = generateRandomOrder(elements.size()); } private int[] generateRandomOrder(int size) { int[] index = new int[size]; for (int i = 0; i < size; i++) { index[i] = i; } int swap; for (int i = 0; i < size; i++) { int randomIndex = getRandomInt(0, size); swap = index[i]; index[i] = index[randomIndex]; index[randomIndex] = swap; } return index; } private int currentIndex = 0; private int getRandomInt(int lowerBound, int upperBound) { return RANDOM.nextInt(upperBound - lowerBound) + lowerBound; } @Override public boolean hasNext() { return currentIndex != elements.size(); } @Override public T next() { return elements.get(order[currentIndex++]); } } 

这仅在您保证列表中的元素位于索引[0,大小]之间的位置时才有效。

如果您担心SecureRandom的性能损失,您可以使用正常的随机数(我更喜欢安全,比普通随机慢8倍但安全!)。

这是一个改组迭代器,在请求少量元素时非常节省空间和时间。 在所有其他情况下,这也是非常合理的; 运行时和空间都是O(n)。 唯一的动态结构是HashMap,其大小只有输入列表的一半(虽然它在开头和结尾附近会小很多)和整数键。

 static  Iterator shuffledIterator(final List l) { return new Iterator() { Random randomizer = new Random(); int i = 0, n = l.size(); HashMap shuffled = new HashMap(); public boolean hasNext() { return i < n; } public A next() { int j = i+randomizer.nextInt(ni); A a = get(i), b = get(j); shuffled.put(j, a); shuffled.remove(i); ++i; return b; } A get(int i) { return shuffled.containsKey(i) ? shuffled.get(i) : l.get(i); } }; }