Reputation:
I have created a method to randomize the list:
public <T> List<T> randomize(List<T> list) {
LinkedList<T> randomizedList = new LinkedList<>();
Random random = new Random(list.size());
for (int i = random.nextInt(); i < list.size(); i++) {
randomizedList.add(list.get(i));
}
return randomizedList;
}
The list that I am passing to this method contains for e.g. five elements. When I am creating Random random = new Random(list.size());
I expect so when I call random.nextInt()
what it will return me the random integer which will be an index of the list element.
But when I call random.nextInt();
instead of returning the number from the interval [0, 4]
(which I expect to be returned) it returns me the value of for e.g.: -349120689
. Which gives me an java.lang.IndexOutOfBoundsException: Index: -349120689, Size: 5
.
Why is this happening and how to solve this?
Upvotes: 0
Views: 4137
Reputation: 13331
new Random(list.size());
this sets the seed of the Random number generator to list.size();
I suggest changing to new Random()
(which will give you a seed based on the current time of the system). Preferably though, you'd want to reuse the same Random object at all times.
random.nextInt();
here is where you'd want to put random.nextInt(list.size());
which will give you a number from 0 to list.size() - 1.
Even with the above changes, your code would just give you a sublist of the list starting at a random index and going until the end. Use Collections.shuffle(list)
instead.
To do a real shuffling, you would need to "remember" which elements you have inserted or not. In pseudo-code, you could do the following:
Upvotes: 3
Reputation: 1500065
I expect so when I call random.nextInt() what it will return me the random integer which will be an index of the list element.
You've misunderstood the purpose of the Random(long)
constructor. The purpose of that constructor is to specify a seed for the list. You don't want to do this - it would mean that every collection of size 5 is always shuffled the same way.
You specify the range on each call to nextInt
. So if you want a random number between 0 (inclusive) and max
(exclusive) you just use:
int value = random.nextInt(max);
However, it would be much better just to use Collections.shuffle
instead of writing your own code to do this - assuming you really want a shuffle (which isn't what your current approach would give you anyway - even after fixing the nextInt
call, you'd end up
with basically a sublist, because nextInt()
is only called once. So if the first call to nextInt()
returns 2 (in a list of 5) you'd end up returning a new list containing the final 3 elements. I strongly suspect that's not what you were trying to do.
As a side-note, when you want to know why an API isn't behaving the way you expect it to, read the documentation. The documentation of the Random(long)
constructor and Random.nextInt()
are pretty clearly not the behaviour you were expecting.
Upvotes: 2
Reputation: 3630
You're confusing the argument to nextInt(n)
(upper bound for the randomization) with the argument to the constructor (random seed). You shoudl use nextInt(list.size)
, and probably, initialize the Random object using new Random()
.
Upvotes: 0
Reputation: 7147
The argument to the Random
constructor is a random seed, not the maximum of what it returns.
Pass the maximum number to nextInt()
instead.
Upvotes: 0
Reputation: 63
use this
public <T> List<T> randomize(List<T> list) {
LinkedList<T> randomizedList = new LinkedList<>();
Random random = new Random();
for (int i = random.nextInt(list.size()); i < list.size(); i++) {
randomizedList.add(list.get(i));
}
return randomizedList;
}
Upvotes: 0