Create a random order of (x, y) pairs, without repeating/subsequent x's

后端 未结 9 2384
陌清茗
陌清茗 2021-02-08 12:25

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

9条回答
  •  生来不讨喜
    2021-02-08 12:57

    An interesting question! Here is my solution. It has the following properties:

    • If there is no valid solution it should detect this and let you know
    • The iteration is guaranteed to terminate so it should never get stuck in an infinite loop
    • Any possible solution is reachable with nonzero probability

    I do not know the distribution of the output over all possible solutions, but I think it should be uniform because there is no obvious asymmetry inherent in the algorithm. I would be surprised and pleased to be shown otherwise, though!

    import random
    
    def random_without_repeats(xs, ys):
        pairs = [[x,y] for x in xs for y in ys]
        output = [[object()], [object()]]
        seen = set()
        while pairs:
            # choose a random pair from the ones left
            indices = list(set(xrange(len(pairs))) - seen)
            try:
                index = random.choice(indices)
            except IndexError:
                raise Exception('No valid solution exists!')
            # the first element of our randomly chosen pair
            x = pairs[index][0]
            # search for a valid place in output where we slot it in
            for i in xrange(len(output) - 1):
                left, right = output[i], output[i+1]
                if x != left[0] and x != right[0]:
                    output.insert(i+1, pairs.pop(index))
                    seen = set()
                    break
            else:
                # make sure we don't randomly choose a bad pair like that again
                seen |= {i for i in indices if pairs[i][0] == x}
        # trim off the sentinels
        output = output[1:-1]
        assert len(output) == len(xs) * len(ys)
        assert not any(L==R for L,R in zip(output[:-1], output[1:]))
        return output
    
    
    nx, ny = 5, 5       # OP example
    # nx, ny = 2, 10      # output must alternate in 1st index
    # nx, ny = 4, 13      # shuffle 'deck of cards' with no repeating suit
    # nx, ny = 1, 5       # should raise 'No valid solution exists!' exception
    
    xs = range(1, nx+1)
    ys = range(1, ny+1)
    
    for pair in random_without_repeats(xs, ys):
        print pair
    

提交回复
热议问题