从Python列表中提取随机子列表

17

我有一个Python字典,如下所示:

{'APPLE_PROVIDERS' : ["some", "provider","can","be", "null"],
  ....
}

我想做的是从键的列表(即一个值)中获取一个随机子列表。不只是一个元素,而是一个完全随机的子列表。以下是我尝试的代码:

a_list = a_dict.get('APPLE_PROVIDERS', "")
for item in a_list[randrange(0,len(a_list)) : randrange(0,len(a_list))]:
  ...do something.. 

这个东西有两个问题:

  1. 如果列表为空,或者字典查找失败,程序会失败,因为randrange的参数为(0,0),这导致出现错误。

  2. 当列表较小时,randrange()调用很多次会生成相同的数字,这将返回一个空列表。例如a_list[5:5]。

那么最好的方法是什么,以处理上述情况?此外,我不关心顺序,任何方式都可以。每次for循环开始时,我只想要一个完全随机的子列表,包含0、1...直到len(a_list)个元素。

如果可以将列表更改为其他可以容纳相似元素的数据结构,那对我也可以。


只是为了明确:您想要从原始列表中随机选择一系列连续的元素吗? - dhke
在你的随机子列表中,是否可以有重复元素?你的随机子列表的长度应该是多少? - ilyas patanam
4个回答

33

示例它。

>>> random.sample(["some", "provider", "can", "be", "null"], 3)
['some', 'can', 'provider']
>>> random.sample(["some", "provider", "can", "be", "null"], 3)
['can', 'null', 'provider']
>>> random.sample(["some", "provider", "can", "be", "null"], 3)
['null', 'some', 'provider']

1
我想要一个子列表,其中包含0、1、2、3...len-1个元素,而不仅仅是一个特定的数字。 - user775093
1
你试过用其他东西替换这个数字吗? - Ignacio Vazquez-Abrams
@user775093,您需要一个“公平”的分配吗? - John La Rooy
公平并不是必要的.. 我想我明白Ignacio在暗示什么。在进行样本之前的循环中,我会随机更改第二个参数,绑定到列表的长度。但这会给出一个不按顺序的子列表吗?还是每次都需要洗牌?例如,我想要一个反向的子列表.. - user775093

7
>>> from random import randint
>>> left = randint(0, len(L))
>>> right = randint(left, len(L))
>>> L[left:right]
['null']

如果您不希望可能出现空列表

>>> left = randint(0, len(L) - 1)
>>> right = randint(left + 1, len(L))

1
但这不会是随机的。您将始终获得与原始列表相同顺序的子列表。如果我正确理解了问题,您还应该能够获得一个不按顺序排列的列表。 - Games Brainiac
@GamesBrainiac,给出的示例代码试图获取一个切片。问题似乎在于该切片经常为空(因为切片的末尾被反转了)。 - John La Rooy

1

Ignacio的回答很棒。如果你想要最小化修改你的代码,你可以这样做:

a_list = a_dict.get('APPLE_PROVIDERS', "")
if len(a_list) > 1:
    index1 = randrange(0,len(a_list)-1)
    index2 = randrange(index1+1,len(a_list))
    for item in a_list[index1:index2]:
        pass #do stuff

我在这里做两件事:1)检查a_list是否有多个元素,2)使用randrange生成索引,但保证第二个大于第一个。

如果要判断一个列表是否非空,可以直接使用 if a_list,避免调用 len() 函数。我还建议将这个函数改为生成器函数(将 pass 替换为 yield item)。 - dhke
if a_list 相当于 if len(a_list) > 0,但两者并不完全相同。是否应该将 pass 替换为 yield 取决于 OP 想要做什么。 - El'endia Starman
@elendia-starman:啊,抱歉,我在脑海中跳过了> 1。而且生成器更具Python风格,特别是考虑到问题的用例。 - dhke

1

假设你希望在获取空列表时返回一个空列表,这里提供一个示例解决方案:

from random import shuffle

def get_random_sublist(the_dict, key, number):
    l = the_dict.get(key, [])
    shuffle(l)
    return l[:number]

所以,我会使用 random.shuffle。这可以避免要求一个比实际列表更大的子列表的问题。

>>> DICT = {'a' : "1 2 3 4 5".split(), 'b': [], 'c': [1]}
>>> get_random_sublist(DICT, 'a', 3)
['4', '1', '2']
>>> get_random_sublist(DICT, 'b', 10)
[]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接