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

后端 未结 9 2272
陌清茗
陌清茗 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 13:02

    This should do what you want.

    rando will never generate the same X twice in a row, but I realized that it is possible (though seems unlikely, in that I never noticed it happen in the 10 or so times I ran without the extra check) that due to the potential discard of duplicate pairs it could happen upon a previous X. Oh! But I think I figured it out... will update my answer in a moment.

    import random
    
    X = [1,2,3,4,5]
    Y = [1,2,3,4,5]
    
    
    def rando(choice_one, choice_two):
        last_x = random.choice(choice_one)
        while True:
            yield last_x, random.choice(choice_two)
            possible_x = choice_one[:]
            possible_x.remove(last_x)
            last_x = random.choice(possible_x)
    
    
    all_pairs = set(itertools.product(X, Y))
    result = []
    r = rando(X, Y)
    while set(result) != all_pairs:
        pair = next(r)
        if pair not in result:
            if result and result[-1][0] == pair[0]:
                continue
            result.append(pair)
    
    import pprint
    pprint.pprint(result)
    
    0 讨论(0)
  • 2021-02-08 13:10

    Here's a solution using NumPy

    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]]
            yield pair
    

    Here's a Jupyter notebook that explains how it works

    Inside the loop, we have to copy the weights, add them up, and choose a random index using the weights. These are all linear in n. So the overall complexity to generate all pairs is O(n^2 m)

    But the runtime is deterministic and overhead is low. And I'm fairly sure it generates all legal sequences with equal probability.

    0 讨论(0)
  • 2021-02-08 13:12

    Here is my solution. First the tuples are chosen among the ones who have a different x value from the previous selected tuple. But I ve noticed that you have to prepare the final trick for the case you have only bad value tuples to place at end.

    import random
    
    num_x = 5
    num_y = 5
    
    all_ys = range(1,num_y+1)*num_x
    all_xs = sorted(range(1,num_x+1)*num_y)
    
    output = []
    
    last_x = -1
    
    for i in range(0,num_x*num_y):
    
        #get list of possible tuple to place    
        all_ind    = range(0,len(all_xs))
        all_ind_ok = [k for k in all_ind if all_xs[k]!=last_x]
    
        ind = random.choice(all_ind_ok)
    
        last_x = all_xs[ind]
        output.append([all_xs.pop(ind),all_ys.pop(ind)])
    
    
        if(all_xs.count(last_x)==len(all_xs)):#if only last_x tuples,
            break  
    
    if len(all_xs)>0: # if there are still tuples they are randomly placed
        nb_to_place = len(all_xs)
        while(len(all_xs)>0):
            place = random.randint(0,len(output)-1)
            if output[place]==last_x:
                continue
            if place>0:
                if output[place-1]==last_x:
                    continue
            output.insert(place,[all_xs.pop(),all_ys.pop()])
    
    print output
    
    0 讨论(0)
提交回复
热议问题