簡體   English   中英

僅當元素尚未存在時,將元素添加到列表的最有效方法是什么?

[英]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. 轉到列表的末尾並添加一個新元素
  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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM