2016-03-01 30 views
1

我試圖生成大小爲num_cities(x, y)元組的列表,其約束條件是沒有兩個元組是相同的。是否有一個更短的Pythonic方法來使用set comprehension或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) 

回答

3

如果最大值不太大,可以存儲一套完整的存儲可能性(和它永遠不會主動來生成),random.sampleitertools.product可以有效地使用在這裏:

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的樣品,然後將它們組合在一起,但這會爲每個軸添加唯一性約束,我猜你不想要。

對於這個特定情況(獨特的數字遵循可預測的模式),您可以使用一種技巧來使這種記憶更友好,同時還避免了任意長的循環問題。而不是採取兩個productrange S,你會生成一個range(或的Py2,xrange)在單個值編碼從product既獨特值:

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] 

這意味着你沒有大(因爲Py3 range/Py2 xrange是「虛擬」序列,存儲需求與它們所代表的值的範圍無關,並且random.sample產生的樣本不需要讀取底層序列的所有值)。

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),但它不會變得更糟如果城市數量的增加。

相關問題