向集合中添加元素还是将列表 a 转换为集合更好?

Is it better to add elements to a set or to convert list a into a set?

我正在为执行聚合的大数据管道创建逻辑。我需要计算一个字段的唯一值的数量,所以我决定使用 set's.

考虑到条目的数量可能很大,我不知道哪种计算唯一元素数量的方法会更好。

我想到了两个办法:

1.创建一个空 set 并将每个条目添加到其中。

myset = set()
for entry in entries:
    myset.add(entry['key'])
uniques = len(myset)

每次新条目到达时,此选项都必须检查该值是否存在于集合中。如果可能取值的个数少,我觉得可能会更快。

2。创建一个列表,将所有条目附加到它并将其转换为一个集合

mylist = list()
for entry in entries:
    mylist.append(entry['key'])
uniques = len(set(mylist))

此选项只会搜索一次唯一值,尽管是在更大的集合中。如果可能值的数量很大(例如:ID 或电子邮件),我认为它可能会更快。


我的假设是否正确?有什么方法可以找到无论条件如何都是最好的唯一值?

让我们创建一个函数来创建我们的条目列表。

def make_entries(size):
    return [{'key': random.randint(1, size//2)} for _ in range(size)]

我们将使用它来创建不同大小的列表并测试每种方法的速度。

方法 1:创建一个空集并添加到其中

def add_to_set(entries):
    myset = set()
    for entry in entries:
        myset.add(entry['key'])
    return len(myset)

方法二:创建一个列表,然后用它来创建一个集合

def create_from_list(entries):
    mylist = list()
    for entry in entries:
        mylist.append(entry['key'])
    return len(set(mylist))

方法 2a:使用列表理解创建列表,然后创建集合

def create_from_list_comprehension(entries):
    return len(set([entry['key'] for entry in entries]))

方法 3:使用集合理解 (@schwobaseggl's suggestion in their )

def set_comprehension(entries):
    return len({entry['key'] for entry in entries})

接下来,我们可以针对不同的 size.

值对这些方法中的每一种进行计时
sizes = [10, 50, 100, 500, 1_000, 5_000, 10_000, 50_000, 100_000]

times = []

for size in sizes:
    times.append([])
    entries = make_entries(size)
    nrepeat = 1000
    times[-1].append(timeit.timeit('add_to_set(entries)', setup='from __main__ import entries, add_to_set', number=nrepeat) / nrepeat)
    times[-1].append(timeit.timeit('create_from_list(entries)', setup='from __main__ import entries, create_from_list', number=nrepeat) / nrepeat)
    times[-1].append(timeit.timeit('create_from_list_comprehension(entries)', setup='from __main__ import entries, create_from_list_comprehension', number=nrepeat) / nrepeat)
    times[-1].append(timeit.timeit('set_comprehension(entries)', setup='from __main__ import entries, set_comprehension', number=nrepeat) / nrepeat)

我 运行 在我的 Win10 笔记本电脑上使用 Python 3.7.7,其中 print(sys.version) 给出

3.7.7 (tags/v3.7.7:d7c567b08f, Mar 10 2020, 10:41:24) [MSC v.1900 64 bit (AMD64)]

现在,如果我们绘制 times,我们会发现使用集合理解始终比所有其他方法更快。

在您提出的两种方法之间,直接添加到集合通常比创建列表然后从该列表创建集合更快,但速度并不快:平均快 1.2 倍。


如果您有兴趣,这些是我为 times 获得的数字。列对应不同的方法,行对应不同的大小。

times = [[1.91180001e-06, 2.25380005e-06, 1.43129996e-06, 7.10900058e-07],
       [4.31230001e-06, 6.94569992e-06, 3.65169998e-06, 2.49419990e-06],
       [1.56470999e-05, 1.50408000e-05, 8.06160003e-06, 5.67660003e-06],
       [6.51685999e-05, 7.41121001e-05, 6.79391000e-05, 4.49675000e-05],
       [1.40047500e-04, 1.70246000e-04, 9.80658000e-05, 6.99476000e-05],
       [8.01188900e-04, 1.00142830e-03, 4.92695100e-04, 5.36500400e-04],
       [1.35429690e-03, 1.53512830e-03, 8.99595700e-04, 8.74221300e-04],
       [8.91747430e-03, 1.10454779e-02, 8.46084390e-03, 7.77944500e-03],
       [1.97166152e-02, 1.95640820e-02, 1.17698472e-02, 1.20813099e-02]]