I want to generate a unique random index everyday to show "word of the day" from N number of words in a list. Until every words are indexed from a list, I dont't want the same index to be repeated. For example, I have N words in a list; the index each day should be different for N days.
3 Answers
If you really can't be bothered to keep a record of the numbers you've already used you could use a rather nice mechanism known as a Linear Feedback Shift Register or LFSR
. This Generates a random (but predictable, if you know it's an LFSR) sequence of numbers spanning all numbers of n
bits.
Just choose n
to be greater than your 'N' and throw away any numbers too big.
/**
* Linear feedback shift register
*
* Taps can be found at: See http://www.xilinx.com/support/documentation/application_notes/xapp052.pdf See http://mathoverflow.net/questions/46961/how-are-taps-proven-to-work-for-lfsrs/46983#46983 See
* http://www.newwaveinstruments.com/resources/articles/m_sequence_linear_feedback_shift_register_lfsr.htm See http://www.yikes.com/~ptolemy/lfsr_web/index.htm See
* http://seanerikoconnor.freeservers.com/Mathematics/AbstractAlgebra/PrimitivePolynomials/overview.html
*
* @author OldCurmudgeon
*/
public class LFSR implements Iterable<BigInteger> {
// Bit pattern for taps.
private final BigInteger taps;
// Where to start (and end).
private final BigInteger start;
// The poly must be primitive to span the full sequence.
public LFSR(BigInteger primitivePoly, BigInteger start) {
// Where to start from (and stop).
this.start = start.equals(BigInteger.ZERO) ? BigInteger.ONE : start;
// Knock off the 2^0 coefficient of the polynomial for the TAP.
this.taps = primitivePoly.shiftRight(1);
}
@Override
public Iterator<BigInteger> iterator() {
return new LFSRIterator(start);
}
private class LFSRIterator implements Iterator<BigInteger> {
// The last one we returned.
private BigInteger last = null;
// The next one to return.
private BigInteger next = null;
public LFSRIterator(BigInteger start) {
// Do not return the seed.
last = start;
}
@Override
public boolean hasNext() {
if (next == null) {
/*
* Uses the Galois form.
*
* Shift last right one.
*
* If the bit shifted out was a 1 - xor with the tap mask.
*/
boolean shiftedOutA1 = last.testBit(0);
// Shift right.
next = last.shiftRight(1);
if (shiftedOutA1) {
// Tap!
next = next.xor(taps);
}
// Never give them `start` again.
if (next.equals(start)) {
// Could set a finished flag here too.
next = null;
}
}
return next != null;
}
@Override
public BigInteger next() {
// Remember this one.
last = hasNext() ? next : null;
// Don't deliver it again.
next = null;
return last;
}
@Override
public void remove() {
throw new UnsupportedOperationException("Not supported.");
}
@Override
public String toString() {
return LFSR.this.toString()
+ "[" + (last != null ? last.toString(16) : "")
+ "-" + (next != null ? next.toString(16) : "") + "]";
}
}
@Override
public String toString() {
return "(" + taps.toString(32) + ")-" + start.toString(32);
}
public static void main(String args[]) {
try {
new LFSRTest().test();
} catch (Throwable t) {
t.printStackTrace(System.err);
}
}
}
class LFSRTest {
public void test(int[] tap, int base) {
System.out.println("Test: " + Arrays.toString(tap));
// Build the BigInteger.
BigInteger primitive = BigInteger.ZERO;
for (int bit : tap) {
primitive = primitive.or(BigInteger.ONE.shiftLeft(bit));
}
// Stop at 100.
int count = 100;
LFSR lfsr = new LFSR(primitive, BigInteger.ONE);
for (BigInteger b : lfsr) {
if (count-- > 0) {
System.out.println(b.toString(base));
} else {
break;
}
}
}
public void test() {
// Just 6 bits.
int[] tap7 = {6, 5, 0};
test(tap7, 10);
// An example 48-bit tap.
int[] tap48 = {48, 46, 45, 44, 42, 40, 36, 34, 33, 32, 29, 27, 26, 20, 17, 16, 12, 11, 10, 5, 3, 1, 0};
test(tap48, 32);
}
}
As you can see, the efficiency is very good - just a few boolean ops per iteration. You can therefore just iterate N
times to get the number you want. Choose the number of bits to achieve at least the number of days you want.

- 64,482
- 16
- 119
- 213
-
i appreciate your effort to write all this code here. But I am sorry this looks too complex for me as I am still a java beginner. – aeruhxi Jan 25 '16 at 16:28
-
I will go with James Loyd's idea of incrementing index over a shuffled array every day. But since my program doesn't run on server, I have to let my application know the new day is entered when it is opened and increment the index, Is there any way to accomplish this? – aeruhxi Jan 25 '16 at 16:31
-
@pratik.gamer if you have a new question, you should post a new question. – Erick G. Hagstrom Jan 25 '16 at 16:34
-
@ErickG.Hagstrom Oh, I am sorry. I will keep that in mind. For now, my problem is resolved. Thank you. – aeruhxi Jan 25 '16 at 16:41
-
Save your shuffled array and your index in a file. The index is kind of optional, as you can use the current date to know how many days have passed. – Bifz Jan 25 '16 at 18:07
-
@OldCurmudgeon No, OP asked here how use the array in a non-continuously running app. – Bifz Jan 26 '16 at 00:24
Here are some steps to get you started:
1) Generate a random number
2) Check this random number against an array/hashmap/list/whatever.
3) If it doesn't exist, add it in
4) Find 'word of the day' using this number.
5) Repeat these steps
If the random number does exist, then simply generate another one. You would then repeat these steps everyday until the size of the 'already used numbers' array matches the length of the 'words of the day' array. However, this process is not very efficicent and I wouldn't necessarily use it, it is just here to get you thinking.
Some possibly better ideas:
If you never want it to be the same, instead of 'randomly generating' a number. Why not just iterate through an array to begin with and increase it every day?
You could also just generate a random number, find the word of the day and then delete it from your list of random words and repeat this process until the list is empty, ensuring you alter the boundaries of your random numbers each time. Then when it is empty, just repopulate it.

- 1,471
- 3
- 23
- 52
-
Very bad performance on day N. Also pretty bad on day N-1, N-2, ... especially if N is high, – Andreas Jan 25 '16 at 16:14
-
shuffling a sequential array once and iterate over it sequential every day sounds an efficient idea. Thanks. But how do i increment index everyday since my perogram doesn't operate on server (can not be online all day)? – aeruhxi Jan 25 '16 at 16:15
-
Please don't downvote just because it's inefficient. I even stated it was inefficient. As they haven't posted any code or given it a real go, I was trying to get them thinking and get them started. I have also suggested a better way of doing it. – James Jan 25 '16 at 16:17
-
Also, on a side note, this can be implemented more efficiently in several ways, such as using hash maps, or instaniating an array the size of your words of the day array and then just fill the index of the random number with true/false and check against that, so you only look at 1 index instead of searching the array. You could also create a 'word' object and give it a name property and a 'used' property and use that to check against. The possibilities are endless. – James Jan 25 '16 at 16:25
-
@pratik.gamer what exactly do you mean? Surely your program needs to be running at least once per day to generate this number? – James Jan 25 '16 at 16:26
-
Yes, I want to let application, as soon as opened, have ability to know whether the new day is entered. Maybe I can get this by saving the track of last day in a file. – aeruhxi Jan 25 '16 at 16:34
Create an array of these possible numbers and shuffle it. Every day use the next index, starting at 0.

- 403
- 2
- 9