6

是否可以只洗牌给定列表(或numpy中的数组)的(连续)部分?

如果这通常是不可能的,那么第一个元素是固定的而列表/数组的其余部分需要改组的特殊情况呢?例如,我有一个列表/数组:

to_be_shuffled = [None, 'a', 'b', 'c', 'd', ...]

第一个元素应始终保留的位置,而其余元素将被反复洗牌。

一种可能的方法是先打乱整个列表,然后检查第一个元素,如果它不是特殊的固定元素(例如None),则将其位置与特殊元素的位置交换(然后需要查找)。

有没有更好的方法来做到这一点?

4

4 回答 4

10

为什么不只是

import random
rest = to_be_shuffled[1:]
random.shuffle(rest)
shuffled_lst = [to_be_shuffled[0]] + rest
于 2012-07-29T03:03:24.990 回答
5

numpy 数组不会在切片时复制数据:

numpy.random.shuffle(a[1:])
于 2012-07-29T04:10:24.933 回答
4

我认为尝试实施比您所要求的更通用的方法会很有趣且具有教育意义。在这里,我将索引打乱到原始列表(而不是列表本身),不包括锁定的索引,并使用该索引列表从原始列表中挑选元素。这不是就地解决方案,而是作为生成器实现的,因此您可以懒惰地选择元素。

如果可以改进,请随时编辑。

import random

def partial_shuf(input_list, fixed_indices):
    """Given an input_list, yield elements from that list in random order
    except where elements indices are in fixed_indices."""
    fixed_indices = sorted(set(i for i in fixed_indices if i < len(input_list)))
    i = 0
    for fixed in fixed_indices:
        aslice = range(i, fixed)
        i = 1 + fixed
        random.shuffle(aslice)
        for j in aslice:
            yield input_list[j]
        yield input_list[fixed]
    aslice = range(i, len(input_list))
    random.shuffle(aslice)
    for j in aslice:
        yield input_list[j]

print '\n'.join(' '.join((str(i), str(n))) for i, n in enumerate(partial_shuf(range(4, 36), [0, 4, 9, 17, 25, 40])))

assert sorted(partial_shuf(range(4, 36), [0, 4, 9, 17, 25, 40])) == range(4, 36)
于 2012-07-29T04:09:26.987 回答
3

我从标准库模块(random在 它做到了这一点。享受!Lib\random.pystartstop

from random import randint

def shuffle(x, start=0, stop=None):
    if stop is None:
        stop = len(x)

    for i in reversed(range(start + 1, stop)):
        # pick an element in x[start: i+1] with which to exchange x[i]
        j = randint(start, i)
        x[i], x[j] = x[j], x[i]

出于您的目的,使用1作为start参数调用此函数应该可以解决问题。

于 2012-07-29T03:43:01.567 回答