<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Solution to a problem posted here
Step1:  Here are some example values for x and y.  I assume that there are no repeated values in x.
Step2:  indices is the list of indices I'll choose from at random
Step3:  Now I'll make an array to hold the values of y
Step4:  And shuffle the rows independently
Step5:  I'll keep track of how many unused ys there are in each row
Step6:  Now I'll choose a row, using the counts as weights
Step7:  i is the row I chose, which corresponds to a value of x.
Step8:  Now I decrement the counter associated with i, assemble a pair by choosing a value of x and a value of y.
I also clobber the array value I used, which is not necessary, but helps with visualization.
Step9:  We can check that the counts got decremented
Step10:  And one of the values in array got used
Step11:  The next time through is almost the same, except that when we assemble the weights, we give zero weight to the index we just used.
Step12:  Everything else is the same
Step13:  Now we can wrap all that up in a function, using a special value for i during the first iteration.
Step14:  And here's how it works
<ASSISTANT_TASK:>
Python Code:
import numpy as np
Explanation: Solution to a problem posted here:
http://stackoverflow.com/questions/36455104/create-a-random-order-of-x-y-pairs-without-repeating-subsequent-xs#
Say I have a list of valid X = [1, 2, 3, 4, 5] and a list of valid Y = [1, 2, 3, 4, 5].
I need to generate all combinations of every element in X and every element in Y (in this case, 25) and get those combinations in random order.
This in itself would be simple, but there is an additional requirement: In this random order, there cannot be a repetition of the same x in succession. For example, this is okay:
[1, 3]
[2, 5]
[1, 2]
...
[1, 4]
This is not:
[1, 3]
[1, 2]  &lt;== the "1" cannot repeat, because there was already one before
[2, 5]
...
[1, 4]
Now, the least efficient idea would be to simply randomize the full set as long as there are no more repetitions. My approach was a bit different, repeatedly creating a shuffled variant of X, and a list of all Y * X, then picking a random next one from that. So far, I've come up with this:
[...]
But I'm sure this can be done even more efficiently or in a more succinct way?
Also, my solution first goes through all X values before continuing with the full set again, which is not perfectly random. I can live with that for my particular application case.
My solution uses NumPy
End of explanation
xs = np.arange(10, 14)
ys = np.arange(20, 25)
print(xs, ys)
Explanation: Here are some example values for x and y.  I assume that there are no repeated values in x.
End of explanation
n = len(xs)
m = len(ys)
indices = np.arange(n)
Explanation: indices is the list of indices I'll choose from at random:
End of explanation
array = np.tile(ys, (n, 1))
print(array)
Explanation: Now I'll make an array to hold the values of y:
End of explanation
[np.random.shuffle(array[i]) for i in range(n)] 
print(array)
Explanation: And shuffle the rows independently
End of explanation
counts = np.full_like(xs, m)
print(counts)
Explanation: I'll keep track of how many unused ys there are in each row
End of explanation
weights = np.array(counts, dtype=float)
weights /= np.sum(weights)
print(weights)
Explanation: Now I'll choose a row, using the counts as weights
End of explanation
i = np.random.choice(indices, p=weights)
print(i)
Explanation: i is the row I chose, which corresponds to a value of x.
End of explanation
counts[i] -= 1
pair = xs[i], array[i, counts[i]]
array[i, counts[i]] = -1
print(pair)
Explanation: Now I decrement the counter associated with i, assemble a pair by choosing a value of x and a value of y.
I also clobber the array value I used, which is not necessary, but helps with visualization.
End of explanation
print(counts)
Explanation: We can check that the counts got decremented
End of explanation
print(array)
Explanation: And one of the values in array got used
End of explanation
weights = np.array(counts, dtype=float)
weights[i] = 0
weights /= np.sum(weights)
print(weights)
Explanation: The next time through is almost the same, except that when we assemble the weights, we give zero weight to the index we just used.
End of explanation
i = np.random.choice(indices, p=weights)
counts[i] -= 1
pair = xs[i], array[i, counts[i]]
array[i, counts[i]] = -1
print(pair)
print(counts)
print(array)
Explanation: Everything else is the same
End of explanation
def generate_pairs(xs, ys):
    n = len(xs)
    m = len(ys)
    indices = np.arange(n)
    
    array = np.tile(ys, (n, 1))
    [np.random.shuffle(array[i]) for i in range(n)]
    
    counts = np.full_like(xs, m)
    i = -1
    for _ in range(n * m):
        weights = np.array(counts, dtype=float)
        if i != -1:
            weights[i] = 0
        weights /= np.sum(weights)
        i = np.random.choice(indices, p=weights)
        counts[i] -= 1
        pair = xs[i], array[i, counts[i]]
        array[i, counts[i]] = -1
        
        yield pair
Explanation: Now we can wrap all that up in a function, using a special value for i during the first iteration.
End of explanation
for pairs in generate_pairs(xs, ys):
    print(pairs)
Explanation: And here's how it works:
End of explanation
<END_TASK>