1 回答

TA貢獻(xiàn)1847條經(jīng)驗(yàn) 獲得超11個(gè)贊
長(zhǎng)話短說:
from random import uniform
def gen_coords(x1, y1, x2, y2, n):
result = set()
# loops for each addition, avoiding duplicates
while len(result) < n:
result.add((uniform(x1, x2), uniform(y1, y2)))
return result
可以說,實(shí)際上:
from random import uniform
def gen_coords(x1, y1, x2, y2, n):
return [(uniform(x1, x2), uniform(y1, y2)) for _ in range(n)]
考慮到碰撞的可能性很小。
假設(shè)“起始坐標(biāo)和終止坐標(biāo)之間”是指在笛卡爾坐標(biāo)系(即平面、2D)中這兩個(gè)角之間的矩形截面中。
并假設(shè)充分實(shí)現(xiàn)“均勻分布”,忽略浮點(diǎn)值的非均勻分布。(即,在任何相等長(zhǎng)度的間隔上,浮點(diǎn)值的數(shù)量不是完全相同,也不是連續(xù)體中浮點(diǎn)值之間的恒定距離)
基本上有三種方法可以確保隨機(jī)生成的點(diǎn)不重復(fù):
從可能值的集合中選擇它們,刪除每個(gè)選擇以避免再次選擇;
在允許的空間內(nèi)生成值,將每個(gè)選擇與之前的選擇進(jìn)行檢查,以避免添加重復(fù)項(xiàng)(并重新選擇值,直到生成新值);
生成值并添加到集合中,直到達(dá)到所需的集合大小,生成后刪除重復(fù)項(xiàng)(如果有)并重復(fù)該過程直至完成。
如果從中選取值的空間大小與目標(biāo)集大小相似,第一個(gè)選項(xiàng)可能是一個(gè)不錯(cuò)的選擇。然而,當(dāng)在某些空間中選取具有隨機(jī)浮點(diǎn)坐標(biāo)的點(diǎn)時(shí),這種情況不太可能發(fā)生。
第二種選擇是最直接的,但如果目標(biāo)集大小很大,則計(jì)算成本可能會(huì)很高,因?yàn)槊總€(gè)新選擇都會(huì)導(dǎo)致更多比較。
第三種選擇涉及更多一些,但在候選目標(biāo)集完成之前避免進(jìn)行比較,如果沖突的可能性很小,這當(dāng)然是最佳選擇。
作為第二個(gè)選擇的變體,您可以選擇一個(gè)目標(biāo)數(shù)據(jù)結(jié)構(gòu),完全避免添加重復(fù)項(xiàng),依靠語言/解釋器比用該語言編寫的任何算法更有效地執(zhí)行檢查。
在Python中,這意味著使用 aset
而不是 a list
,這是實(shí)現(xiàn)結(jié)果的最快方法,并且可能是您在第三個(gè)選項(xiàng)中檢查重復(fù)項(xiàng)的方法 - 所以您也可以立即使用它并使用第二個(gè)選項(xiàng)的變體。
請(qǐng)注意,如果您嘗試在選擇函數(shù)的范圍內(nèi)創(chuàng)建大于選擇函數(shù)域的集合,則第二個(gè)和第三個(gè)選項(xiàng)都有一個(gè)重大缺陷。但對(duì)于給定的問題,除了非常大的“n”之外,這是不可能的。
解決方案(將第二個(gè)選項(xiàng)與第三個(gè)選項(xiàng)進(jìn)行比較):
from random import uniform
from timeit import timeit
def pick_coords_restricted(x1, y1, x2, y2, n):
result = set()
# loops for each addition, avoiding duplicates
while len(result) < n:
result.add((uniform(x1, x2), uniform(y1, y2)))
return result
def pick_coords_checked(x1, y1, x2, y2, n):
result = []
# loops once for attempt, checking after each iteration
while len(set(result)) < n:
if len(result) > 0:
result = list(set(result))
result += [(uniform(x1, x2), uniform(y1, y2)) for _ in range(n - len(result))]
else:
result = [(uniform(x1, x2), uniform(y1, y2)) for _ in range(n)]
return result
print(timeit(lambda: pick_coords_restricted(0, 0, 1, 1, 1000), number=10000))
print(timeit(lambda: pick_coords_checked(0, 0, 1, 1, 1000), number=10000))
結(jié)果(在我的硬件上):
4.3799341
3.9363368000000003
我得到了一致的、但稍微更好的函數(shù)結(jié)果pick_coords_checked——我贊成第一個(gè)實(shí)現(xiàn)的清晰度。
添加回答
舉報(bào)