为了账号安全,请及时绑定邮箱和手机立即绑定

就地改组列表的一部分

就地改组列表的一部分

largeQ 2022-10-25 10:18:51
我有一个list,我想就地洗牌它的一部分。我知道random.shuffle()并且它可以就地工作,但是如果我对列表进行切片,它会打乱原始输入的切片副本,而原始输入list保持不变:import randoml = list(range(20))print(l)# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]random.shuffle(l[:10])  # I wish it was shuffling the first halfprint(l)  # but does nothing to `l`# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]我有什么选择?
查看完整描述

3 回答

?
人到中年有点甜

TA贡献1895条经验 获得超7个赞

不是真的到位,但具有预期的结果:


import random


l = list(range(20))


lpart = l[:10]

random.shuffle(lpart)


l[:10] = lpart


print(l)


查看完整回答
反对 回复 2022-10-25
?
守着一只汪

TA贡献1872条经验 获得超3个赞

修改列表 n-place 不会仅对列表的一部分起作用。您可以改为使用random.sample不替换的随机样本,然后切片分配:


k = 10

l[:k] = random.sample(l[:k], k=k)

print(l)

# [1, 7, 6, 0, 2, 3, 4, 9, 8, 5, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]


查看完整回答
反对 回复 2022-10-25
?
慕慕森

TA贡献1856条经验 获得超17个赞

可以使用Fisher-Yates shuffle从根本上重新实现random.shuffle()以接受 afirstlastindex 作为参数,例如:


import random



def valid_index(i, n):

    assert(-n <= i < n)

    return i % n



def shuffle(seq, first=0, last=-1, rand_int_gen=None):

    n = len(seq)

    first = valid_index(first, n)

    last = valid_index(last, n)

    # use Fisher-Yates shuffle (Durstenfeld method)

    if callable(rand_int_gen):

        for i in range(first, last):

            j = rand_int_gen(i, last)

            seq[i], seq[j] = seq[j], seq[i]

    else:

        getrandbits = random.getrandbits

        for i in range(first, last + 1):

            size = last - i + 1

            j = getrandbits(size.bit_length()) % size + i

            seq[i], seq[j] = seq[j], seq[i]

    return seq

像这样使用:


l = list(range(20))

print(l)

# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]


random.seed(0)  # just to show reproducible results

shuffle(l, 0, 9)

print(l)

# [6, 7, 2, 5, 8, 4, 9, 3, 0, 1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

从时间上看,这实际上比random.shuffle()改组整个序列还要快几个百分点。


这本质上更快,因为它直接从中获取随机值,random.getrandbits()这是用于随机整数生成的最接近的方法random,其他方法,例如randint()并randrange()最终减少到这个。最后两个最终在内部使用_getrandbelow(),这可能会getrandbits()更频繁地调用必要的。


for k in range(1, 7): 

    n = 10 ** k 

    print(n) 

    %timeit l = list(range(n)); random.shuffle(l) 

    %timeit l = list(range(n)); shuffle(l) 

    print() 

10

100000 loops, best of 3: 6.16 µs per loop

100000 loops, best of 3: 3.85 µs per loop


100

10000 loops, best of 3: 54.3 µs per loop

10000 loops, best of 3: 28 µs per loop


1000

1000 loops, best of 3: 585 µs per loop

1000 loops, best of 3: 341 µs per loop


10000

100 loops, best of 3: 6.01 ms per loop

100 loops, best of 3: 3.56 ms per loop


100000

10 loops, best of 3: 71.7 ms per loop

10 loops, best of 3: 44.1 ms per loop


1000000

1 loop, best of 3: 815 ms per loop

1 loop, best of 3: 582 ms per loop

正如@usr2564301 所指出的,这里也建议了这种方法。不幸的是,我认为没有更好的方法可以就地执行此操作。


查看完整回答
反对 回复 2022-10-25
  • 3 回答
  • 0 关注
  • 100 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信