在某些库代码中,我有一个可以包含 50,000 项或更多项的列表。
库的调用者可以调用导致字符串被添加到列表中的方法。如何有效地检查要添加的字符串的唯一性?
目前,在添加字符串之前,我会扫描整个列表并将每个字符串与要添加的字符串进行比较。这开始显示超过 10,000 个项目的规模问题。
我将对此进行基准测试,但对洞察力感兴趣。
- 如果我将 List<> 替换为 Dictionary<> ,随着列表增加到 10,000 个或更多项目, ContainsKey() 会明显更快吗?
- 如果我将唯一性检查推迟到添加所有项目之后,它会更快吗?那时我需要检查每个元素与其他元素,仍然是 n^^2 操作。
编辑
一些基本的基准测试结果。我创建了一个抽象类,它公开了 2 个方法:填充和扫描。Fill 只是用 n 个项目填充集合(我使用了 50,000 个)。Scan 扫描列表 m 次(我使用了 5000 次)以查看是否存在给定值。然后我为 List 构建了该类的实现,为 HashSet 构建了另一个实现。
使用的字符串长度统一为 11 个字符,通过抽象类中的方法随机生成。
一个非常基本的微基准。
Hello from Cheeso.Tests.ListTester
filling 50000 items...
scanning 5000 items...
Time to fill: 00:00:00.4428266
Time to scan: 00:00:13.0291180
Hello from Cheeso.Tests.HashSetTester
filling 50000 items...
scanning 5000 items...
Time to fill: 00:00:00.3797751
Time to scan: 00:00:00.4364431
因此,对于该长度的字符串,HashSet 在扫描唯一性时大约比 List 快 25 倍。此外,对于这种大小的集合,在向集合中添加项目时,HashSet 对 List 的惩罚为零。
结果很有趣且无效。为了得到有效的结果,我需要做热身间隔,多次试验,随机选择实施。但我相信这只会稍微改变标准。
感谢大家。
编辑2
在添加随机化和多次试验后,HashSet 在这种情况下始终优于 List,大约 20 倍。
这些结果不一定适用于可变长度的字符串、更复杂的对象或不同的集合大小。