【问题标题】:how do i remove an item from a list and add it to the end of the same list如何从列表中删除项目并将其添加到同一列表的末尾
【发布时间】:2020-05-09 03:04:01
【问题描述】:

我有一个包含 52 个元组(一副扑克牌)的列表,我试图在不使用 random.shuffle 的情况下对其进行洗牌(不允许将其用于此项目)。我要做的是创建 2 个随机索引,从列表中删除这些项目并将 1 放在列表的前面和 1 的末尾。

我可以创建随机#,但不确定如何移动它们。似乎 .pop 是我最好的方法,但不确定这是否正确。

def shuffle():
    ite = 0
    while ite <= 1000:
        rand1 = randint(0, len(card_deck) -1)
        rand2 = randint(0, len(card_deck) -1)
        card_deck.pop[rand1]
        card_deck.append(rand1)
        ite += 1
shuffle()

【问题讨论】:

标签: python list shuffle


【解决方案1】:

Pop 的时间复杂度在这种情况下并不理想。将 rand1 中的值存储为临时变量并将其替换为 rand2 中的值,然后将 rand2 中的值替换为临时变量会更有意义。更有效的是,正如下面评论中提到的,您可以在没有临时变量的情况下交换两个值。

例如,如果您有一个包含 1000 个项目的列表,并且您想弹出第 500 个项目,它将在 N(500) 时间内运行。而您可以在恒定时间内访问列表中的项目。

如果您将此作为家庭作业,请尽量不要在没有自己实施的情况下查看我下面的答案。

def shuffle():
    ite = 0
    while ite <= 1000:
        rand1 = randint(0, len(card_deck) - 1)
        rand2 = randint(0, len(card_deck) - 1)
        card_deck[rand1], card_deck[rand2] = card_deck[rand2], card_deck[rand1]
        ite += 1

【讨论】:

  • 不需要临时存储变量。 Python有元组赋值x, y = y, x
  • 感谢您指出这一点。我已更新我的答案以反映您的反馈。
【解决方案2】:

我想这就是你要找的东西

import random

def build_deck():
    '''
    build a fresh sorted deck of cards
    '''
    nums = range(1,14)
    types = ['Heart','Spade','Club','Diamond']
    deck = [(x,y) for x in types for y in nums]
    return deck


def get_random_indices(from_=1,to=50):
    '''
    get 2 random indices to choose from which are not similar
    '''
    index1 = random.randint(from_,to)
    index2 = random.randint(from_,to)
    if index1 == index2:
        index1,index2 = get_random_indices(from_,to)
    return index1,index2


def shuffle_deck(deck,n_times=52):
    '''
    shuffle deck n times
    '''
    if n_times>0:
        index1,index2 = get_random_indices()
        card1 = deck.pop(index1)
        card2 = deck.pop(index2)
        deck.append(card1)
        deck.insert(0,card2)
        n_times-=1
        shuffle_deck(deck,n_times=n_times)
    return deck

deck = build_deck()
new_deck = shuffle_deck(deck,52)
new_deck

您可以通过使用random.choice()选择是插入还是附加card1来添加额外的随机性

【讨论】:

    【解决方案3】:

    正如@Sean Payne 指出的那样; pop() 不是要走的路。当您只想交换值时,pop() 非常慢。 Python 允许(鼓励)元组赋值,因此可以在不使用临时存储位置 x, y = y, x 或在本例中为 deck[i], deck[j] = deck[j], deck[i] 的情况下交换值。

    for 循环比 while 循环更符合 Python 风格。

    我猜你的导师正试图让你写一个正确的 Knuth shuffle (link),也称为 Fisher-Yates 或 Fisher-Yates-Knuth。 Durstenfeld 是该算法的另一个重要贡献者。

    import random
    
    def shuffle(deck):
        for i in range(len(deck)-1, 0, -1):
            j = random.randint(0,i)
            deck[i], deck[j] = deck[j], deck[i]
        return deck
    
    mydeck = list(range(52))
    print(mydeck)
    print(shuffle(mydeck))
    

    Try it online!

    要注意的最大区别是,一旦您选择了要处理的列表末尾的项目,请将其保留在那里。如果您继续生成允许重新洗牌的项目的数字,它实际上会降低洗牌的随机性。 Mike BostockJeff Atwood 对这个问题都有很好的解释。

    如果你真的想要前后移动,你可以这样做

    import random
    
    def shuffle2(deck):
        back_of_deck = len(deck) - 1
        for i in range(len(deck)//2):
            front = random.randint(i,back_of_deck)
            back = random.randint(i,back_of_deck)
            deck[i], deck[front] = deck[front], deck[i]
            deck[back_of_deck], deck[back] = deck[back], deck[back_of_deck]
            back_of_deck -= 1
        return deck
    
    mydeck = list(range(52))
    print(mydeck)
    print(shuffle2(mydeck))
    

    Try it online!

    【讨论】:

      猜你喜欢
      • 2018-07-27
      • 1970-01-01
      • 2023-01-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-21
      相关资源
      最近更新 更多