Python随机列表理解

2024-03-28 13:36:01 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个类似的列表:

[1 2 1 4 5 2 3 2 4 5 3 1 4 2] 

我想从这个列表中创建一个x个随机元素的列表,其中没有一个元素是相同的。最困难的是我想用列表理解来完成这个任务。。。 因此,如果x=3,可能的结果是:

[1 2 3]
[2 4 5]
[3 1 4]
[4 5 1]

等等。。。

谢谢!

我应该指定不能将列表转换为集合。对不起的! 我需要对随机选择的数字进行加权。所以如果1在列表中出现4次,3在列表中出现2次,那么1被选中的可能性是2倍。。。


Tags: 元素列表数字可能性
3条回答

如果我能正确理解你的问题,这应该行得通:

def weighted_sample(L, x):
    # might consider raising some kind of exception of len(set(L)) < x

    while True:
        ans = random.sample(L, x)
        if len(set(ans)) == x:
            return ans

如果你想要很多这样的样品,你可以做如下的事情:

[weighted_sample(L, x) for _ in range(num_samples)]

我很难想象对抽样逻辑的理解不仅仅是模糊的。逻辑有点太复杂了。对我来说,这听起来像是一个随机的附加在家庭作业上的东西。

如果你不喜欢无限循环,我还没有试过,但我认为这是可行的:

def weighted_sample(L, x):

    ans = []        
    c = collections.Counter(L)  

    while len(ans) < x:
        r = random.randint(0, sum(c.values())
        for k in c:
            if r < c[k]:
                ans.append(k)
                del c[k]
                break
            else:
                r -= c[k]
        else:
            # maybe throw an exception since this should never happen on valid input

     return ans

免责声明:“使用列表理解”的要求是荒谬的。

此外,如果您想使用权重,在Eli Bendersky的weighted random sampling页面上列出了许多优秀的方法。

以下是低效,不可扩展等

也就是说,它不是一个而是两个(两个!)列表理解,返回列表,从不重复元素,并在某种意义上尊重权重:

>>> s = [1, 2, 1, 4, 5, 2, 3, 2, 4, 5, 3, 1, 4, 2]
>>> [x for x in random.choice([p for c in itertools.combinations(s, 3) for p in itertools.permutations(c) if len(set(c)) == 3])]
[3, 1, 2]
>>> [x for x in random.choice([p for c in itertools.combinations(s, 3) for p in itertools.permutations(c) if len(set(c)) == 3])]
[5, 3, 4]
>>> [x for x in random.choice([p for c in itertools.combinations(s, 3) for p in itertools.permutations(c) if len(set(c)) == 3])]
[1, 5, 2]

。。或者,按照FMc的简化:

>>> [x for x in random.choice([p for p in itertools.permutations(s, 3) if len(set(p)) == 3])]
[3, 5, 2]

(我将把x for x放在那里,即使不简单地写list(random.choice(..))或仅仅把它作为元组..)

一般来说,您不想在列表理解中做这种事情——这将导致更难阅读代码。然而,如果你真的必须这样做,我们可以写一个非常可怕的1行:

>>> values = [random.randint(0,10) for _ in xrange(12)]
>>> values
[1, 10, 6, 6, 3, 9, 0, 1, 8, 9, 1, 2]
>>> # This is the 1 liner -- The other line was just getting us a list to work with.
>>> [(lambda x=random.sample(values,3):any(values.remove(z) for z in x) or x)() for _ in xrange(4)]
[[6, 1, 8], [1, 6, 10], [1, 0, 2], [9, 3, 9]]

请不要使用这个代码——我只是出于好玩/学术的原因才发的。

其工作原理如下:

我在列表理解中创建了一个函数,默认参数是从输入列表中随机选择的3个元素。在函数内部,我将元素从values中移除,这样它们就不能再被拾取。由于list.remove返回None,我可以使用any(lst.remove(x) for x in ...)删除值并返回False。由于any返回False,因此在调用函数时,我们命中了or子句,该子句只返回x(带有3个随机选择项的默认值)。剩下的就是调用函数,让魔法发生。

这里的一个问题是,您需要确保您请求的组数(这里我选择了4)乘以每个组的项数(这里我选择了3)小于或等于输入列表中的值数。这看起来很明显,但无论如何可能值得一提。。。

下面是我将shuffle放入列表理解的另一个版本:

>>> lst = [random.randint(0,10) for _ in xrange(12)]
>>> lst
[3, 5, 10, 9, 10, 1, 6, 10, 4, 3, 6, 5]
>>> [lst[i*3:i*3+3] for i in xrange(shuffle(lst) or 4)]
[[6, 10, 6], [3, 4, 10], [1, 3, 5], [9, 10, 5]]

这比我的第一次尝试要好得多,但是,大多数人仍然需要停下来,挠挠头,然后才知道这段代码在做什么。我仍然断言,多行这样做会更好。

相关问题 更多 >