![](/img/trans.png)
[英]What is the most efficient way to find the index of an element in a list, given only an element of a sublist (Python)
[英]What is the most efficient way to add an element to a list only if isn't there yet?
我在Python中有以下代碼:
def point_to_index(point):
if point not in points:
points.append(point)
return points.index(point)
這段代碼非常低效,特別是因為我希望points
增長到容納幾百萬個元素。
如果該點不在列表中,我將遍歷列表3次:
如果是在列表中,我穿越了兩遍:1.尋找它,並決定它是有2去幾乎到了列表的末尾,直到我找到指數
有沒有更有效的方法來做到這一點? 例如,我知道:
所以,如果我有這條線:
if point not in points:
從結尾到開頭搜索列表,當點已經在列表中時,它將提高性能。
但是,我不想這樣做:
if point not in reversed(points):
因為我認為reversed(points)
本身會帶來巨大的代價。
我也不想在列表的開頭添加新的點(假設我知道如何在Python中這樣做)因為這會改變索引,索引必須保持不變才能使算法工作。
我能想到的唯一改進是只使用一次傳遞來實現該功能,如果可能的話,從最后到開始。 底線是:
編輯:我已經得到了只用一次通過實現這個的建議。 index()
有沒有辦法從最后到開頭?
編輯:人們已經問過為什么索引是關鍵的。 我正在嘗試使用OFF文件格式描述3D表面。 此格式使用其頂點和面來描述曲面。 首先列出頂點,然后使用頂點索引列表描述面。 這就是為什么一旦我向列表中添加一個漩渦,它的索引就不能改變。
編輯:有一些建議(如igor )使用dict。 這是掃描列表的好方法。 但是,當我完成后,我需要按照創建的順序打印出列表。 如果我使用dict,我需要打印出按值排序的鍵。 有沒有一個好方法呢?
編輯:我實施了www.brool.com的建議 。 這是最簡單,最快速的。 它本質上是一個有序的Dict,但沒有開銷。 表現很棒!
你想使用一套 :
>>> x = set()
>>> x
set([])
>>> x.add(1)
>>> x
set([1])
>>> x.add(1)
>>> x
set([1])
集合僅包含您添加的任何項目的一個實例,並且比手動迭代列表更有效。
如果您以前沒有在Python中使用過套點,那么這個wikibooks頁面看起來就像一個很好的入門。
這將最多遍歷一次:
def point_to_index(point):
try:
return points.index(point)
except ValueError:
points.append(point)
return len(points)-1
您可能還想嘗試此版本,其中考慮到匹配可能接近列表的末尾。 請注意,即使在非常大的列表上, reversed()
也幾乎沒有成本 - 它不會創建副本,也不會多次遍歷列表。
def point_to_index(point):
for index, this_point in enumerate(reversed(points)):
if point == this_point:
return len(points) - (index+1)
else:
points.append(point)
return len(points)-1
您可能還會考慮保留並行dict
或一set
點來檢查成員資格,因為這兩種類型都可以在O(1)中進行成員資格測試。 當然,會有大量的內存成本。
顯然,如果以某種方式對點進行排序,那么您將有許多其他選項來加速此代碼,特別是使用二進制搜索進行成員資格測試。
如果您擔心內存使用情況,但想要優化常見情況,請保留包含最后n個點及其索引的字典。 points_dict = dictionary,max_cache =緩存的大小。
def point_to_index(point):
try:
return points_dict.get(point, points.index(point))
except:
if len(points) >= max_cache:
del points_dict[points[len(points)-max_cache]]
points.append(point)
points_dict[points] = len(points)-1
return len(points)-1
def point_to_index(point):
try:
return points.index(point)
except:
points.append(point)
return len(points)-1
更新:在Nathan的異常代碼中添加。
正如其他人所說,考慮使用set或dict。 你不解釋為什么你需要索引。 如果他們只需要為點分配唯一ID(我不能輕易想出使用它們的另一個原因),那么dict確實會更好地工作,例如,
points = {}
def point_to_index(point):
if point in points:
return points[point]
else:
points[point] = len(points)
return len(points) - 1
你真正想要的是一個有序的字典(鍵插入確定順序):
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.