在 Java 中随机迭代 ArrayList<Integer>
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3887262/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Randomly iterate over ArrayList<Integer> in Java
提问by Jungle Hunter
Seems a very basic question. I've an ArrayList<Integer> al
and I would like to iterate over it. Normally,
似乎是一个非常基本的问题。我有一个ArrayList<Integer> al
,我想迭代它。一般,
for(int i : al) {
// some code
}
does the trick. But my requirement is to iterate not in sequence but randomly.
诀窍。但我的要求是不是按顺序而是随机迭代。
回答by NullUserException
You can use Collections.shuffle()
on the list.
你可以使用Collections.shuffle()
就行了。
Note that this will shuffle the list itself, so if order is important you should make a copy of it (and shuffle the copy).
请注意,这将随机播放列表本身,因此如果顺序很重要,您应该制作它的副本(并随机播放副本)。
List<Customer> newList = new ArrayList<>( oldList ) ;
Collections.shuffle( newList ) ;
Alternatively you could create a random array which has elements 0 - List.size()-1
and using those as indices to access "random" elements in the List
.
或者,您可以创建一个随机数组,其中包含元素0 - List.size()-1
并使用这些元素作为索引来访问List
.
回答by aykutfirat
Use the following class:
使用以下类:
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;
}
}
回答by Christian Bongiorno
How about this way (more functional); it even includes a main() to demonstrate. Basically, generate random numbers in the range of your list size until you have 1 of them all. We use HashSet to take care of duplicate random numbers in our range. Then, delegate iteration to the iterator of your index hashset. Logic of "hasNext()" becomes trivial through delegate.
这种方式怎么样(更实用);它甚至包括一个 main() 来演示。基本上,在您的列表大小范围内生成随机数,直到您拥有其中的 1 个。我们使用 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());
}
}
If you just want an print 100 random numbers:
如果您只想打印 100 个随机数:
IntStream.generate(r::nextInt).limit(100).forEach(System.out::println);
if you want an iterator (for whatever reason:)
如果你想要一个迭代器(无论出于何种原因:)
IntStream.generate(r::nextInt).limit(100).boxed().collect(Collectors.toList()).iterator();
回答by Zpetkov
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++]);
}
}
This only works if you guarantee that the elements in the list are placed in positions exactly between indexes [0,size).
这仅在您保证列表中的元素正好位于索引 [0,size) 之间的位置时才有效。
You can use the normal Random if you are concerned about the performance penalty of SecureRandom (I prefer secure, yeah 8 times slower than normal random but secure!).
如果您担心 SecureRandom 的性能损失,您可以使用普通 Random(我更喜欢安全,是的,比普通随机慢 8 倍但安全!)。
回答by Stefan Reich
Here is a shuffling iterator that is very space&time-efficient when requesting only a few elements. It's very reasonable in all other cases too; runtime and space are both O(n). The only dynamic structure is a HashMap with up to half the size of the input list (although it will be much smaller near the beginning and the end) and Integer keys.
这是一个混洗迭代器,当只请求几个元素时,它非常节省空间和时间。在所有其他情况下也是非常合理的;运行时间和空间都是 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);
}
};
}