[英]Randomly iterate over ArrayList<Integer> in Java
似乎是一个非常基本的问题。 我有一个ArrayList<Integer> al
,我想迭代它。 一般,
for(int i : al) {
// some code
}
诀窍。 但我的要求是不是按顺序迭代而是随机迭代。
您可以在列表中使用Collections.shuffle()
。
请注意,这将使列表本身洗牌,因此如果订单很重要,您应该复制它(并随机播放副本)。
List<Customer> 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<Long> {
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;
}
}
这种方式怎么样(功能更强); 它甚至包括一个main()来演示。 基本上,在列表大小范围内生成随机数,直到您拥有其中一个。 我们使用HashSet来处理我们范围内的重复随机数。 然后,将迭代委托给索引hashset的迭代器。 “hasNext()”的逻辑通过委托变得微不足道。
public class RandomIterator<T> implements Iterator<T> {
private Iterator<Integer> indicies;
List<T> delegate;
public static void main(String[] args) {
Random r = new Random();
List<Integer> numbers = IntStream.generate(r::nextInt).limit(10).boxed().collect(toCollection(ArrayList::new));
List<Integer> results = new ArrayList<>();
for(RandomIterator<Integer> 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<T> delegate) {
Random r = new Random();
this.delegate = delegate;
Set<Integer> 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<T> implements Iterator<T> {
private static final SecureRandom RANDOM = new SecureRandom();
private final int[] order;
private final List<T> elements;
public RandomIterator(List<T> 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 <A> Iterator<A> shuffledIterator(final List<A> l) {
return new Iterator<A>() {
Random randomizer = new Random();
int i = 0, n = l.size();
HashMap<Integer, A> shuffled = new HashMap();
public boolean hasNext() { return i < n; }
public A next() {
int j = i+randomizer.nextInt(n-i);
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);
}
};
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.