Pythonic方法生成一个没有重复的特定大小的列表?

时间:2016-03-01 00:40:14

标签: python

我正在尝试生成(x, y)大小为num_cities的元组列表,其约束条件是没有两个元组是相同的。使用集合理解或itertools是否有更短的Pythonic方法?我目前有:

def make_random_cities(num_cities, max_x, max_y):    
    cities = set()
    while len(cities) < num_cities:
        x, y = randint(0, max_x), randint(0, max_y)
        cities.add((x, y))
    return list(cities)

2 个答案:

答案 0 :(得分:3)

如果最大值不是太大而无法在内存中存储完整的可能性(并且它不会永远生成它们),random.sampleitertools.product可以在这里有效使用:

C:\Projects\TestAndroid\app\build\intermediates\res\merged\debug\values-v21\values-v21.xml
Error:(13) Error retrieving parent for item: No resource found that matches the given name 'android:TextAppearance.Material.Inverse'.
Error:(15) Error retrieving parent for item: No resource found that matches the given name 'android:TextAppearance.Material.Large.Inverse'.
Error:(21) Error retrieving parent for item: No resource found that matches the given name 'android:TextAppearance.Material.Medium.Inverse'.
Error:(206) Error retrieving parent for item: No resource found that matches the given name 'android:Widget.Material.ProgressBar'.
Error:(208) Error retrieving parent for item: No resource found that matches the given name 'android:Widget.Material.ProgressBar.Horizontal'.
Error:(216) Error retrieving parent for item: No resource found that matches the given name 'android:Theme.Material'.
Error:(223) Error retrieving parent for item: No resource found that matches the given name 'android:Theme.Material.Light'.

C:\Projects\TestAndroid\app\build\intermediates\exploded-aar\com.android.support\appcompat-v7\23.0.0\res\values-v21\values-v21.xml
Error:(82, 5) No resource found that matches the given name: attr 'android:colorAccent'.
Error:(82, 5) No resource found that matches the given name: attr 'android:colorButtonNormal'.
Error:(82, 5) No resource found that matches the given name: attr 'android:colorControlActivated'.
Error:(82, 5) No resource found that matches the given name: attr 'android:colorControlHighlight'.

如果输入的import itertools import random def make_random_cities(num_cities, max_x, max_y): return random.sample(list(itertools.product(range(max_x+1), range(max_y+1))), num_cities) 太大,你可能很容易超过主内存;在这种情况下,循环的方法直到获得足够的独特结果可能是最好的方法。

你可以独立完成每个product的样本,然后将它们组合在一起,但这会给每个轴增加唯一性约束,我猜你不想要。

对于这种特定情况(遵循可预测模式的唯一数字),您可以使用技巧使这种内存友好,同时仍然避免任意长循环的问题。您不必获取两个range的{​​{1}},而是生成一个product(或在Py2中,range),它对来自{的两个唯一值进行编码{1}}只有一个值:

range

这意味着您没有要存储的大型中间数据(因为Py3 xrange / Py2 product是&#34;虚拟&#34;序列,其存储要求与它们代表的值范围无关,def make_random_cities(num_cities, max_x, max_y): max_xy = (max_x+1) * (max_y+1) xys = random.sample(range(max_xy), num_cities) return [divmod(xy, max_y+1) for xy in xys] 生成样本而无需读取基础序列的所有值。)

答案 1 :(得分:2)

如果城市数量远小于max_x * max_y,您当前的代码可能会很好。如果它们更靠近在一起,可能会浪费大量时间来生成重复坐标。

另一种方法是生成所有可能的坐标,然后从中进行采样:

possible_coords = list(itertools.product(range(max_x), range(max_y))
sample = random.sample(possible_coords, len(cities))

生成列表将始终采用O(max_x * max_y),但如果城市数量增加则不会变得更糟。