M: Give me a generic algorithm for a function, which gives a random integer, but only one that hasn’t been selected within the last N times that this function has been called for the same purpose. A real world example: I have a playlist with 2000 songs and, when I put it on shuffle with repeat on, I want to make sure that the song that comes up at least hasn’t been played within the last 50 songs. I don’t know if there’s any “official“ algorithmic language, but if there is please give me the answer in whatever one is considered most universal; otherwise, just do your best

G: [Non-text content: thoughts; content_type=thoughts]

G: [Non-text content: reasoning_recap; content_type=reasoning_recap]

G: TL;DR
Maintain a fixed-size “history” buffer (queue) and a matching set. On each request, pick a random candidate and reject it if it’s in the set, then enqueue it and evict the oldest when the buffer exceeds N.


Data structures


1. Rejection-sampling algorithm

function init(M, N):
    historyQueue ← empty queue
    historySet ← empty set

function next():
    require N < M
    repeat:
        x ← random integer in [0 … M−1]
    until x ∉ historySet

    historyQueue.enqueue(x)
    historySet.add(x)

    if historyQueue.size > N:
        y ← historyQueue.dequeue()
        historySet.remove(y)

    return x

2. Alternative: dynamic “allowed” list

function init(M, N):
    allowedList ← list of [0…M−1]
    historyQueue ← empty queue

function next():
    if allowedList.empty:
        // no candidates left outside history; handle as you wish
    i ← random index in [0 … allowedList.size−1]
    x ← allowedList[i]

    historyQueue.enqueue(x)
    allowedList.removeAt(i)

    if historyQueue.size > N:
        y ← historyQueue.dequeue()
        allowedList.append(y)

    return x

3. Full-shuffle option (no repeats until exhaustion)

If you prefer no repeats until all M items have played (then reshuffle):

  1. Create an array A = [0…M−1].
  2. On init or when A becomes empty, shuffle it via Fisher–Yates.
  3. next() simply pops and returns A.pop() until empty.

Third consideration: when N ≥ M