用C#过滤集合的最快方法

3

我有一个对象集合,想要检索出所有具有某个属性匹配搜索字符串的对象。到目前为止,我已经尝试了几种过滤方法,包括List.ForAll、IEnumerable.Where和ParallelQuery.Where。

List<Foo> cache = GetAllObjs(); // source list containing lots of objects

选项1:

List<Foo> foos = cache.AsParallel().Where(x => x.Name == "bar").ToList();

选项2:

List<Foo> foos = cache.Where(x => x.Name == "bar").ToList();

选项三:

List<Foo> foos = cache.FindAll(x => x.Name == "bar");

由于ParallelQuery.Where利用了多个核心,因此它似乎是最快的解决方案。除此之外,还有其他过滤方法,例如使用不同的集合类型或过滤函数吗?源集合不必是List。


5
比赛马(http://ericlippert.com/2012/12/17/performance-rant/)......这可能取决于数组的大小和其他因素。 - Sayse
1
我已经比赛了马匹...至少是我能想到的那三匹。我在想是否有其他不同的马可以替代参加比赛... - painiyff
很难说哪个选项是最好的(给定的选项),就像我说的,对于较小的数组/列表,并行线程的启动时间可能不会在执行时间方面提供任何好处。调用 ToList 也可能是不必要的。 - Sayse
1个回答

14
除此之外,是否还有其他过滤方法,例如使用不同的集合类型或过滤函数?
如果您可以拥有多个具有相同名称的对象,则可以使用Lookup<string, Foo>。您可以将查找视为一个 string -> List<Foo> 字典:
// create
var foosByName = GetAllObjs().ToLookup(x => x.Name, x => x);

// search
var barFoos = foosByName["bar"].ToList();

当然,如果每个名称只有一个Foo,那么经典的Dictionary<string, Foo>就可以胜任。

在字典或查找中搜索(通常)是O(1)操作,而您问题中的搜索方法是O(n)。


2
哇,我改用了 Lookup<string, Foo> 数据结构,这使得搜索几乎瞬间完成了。因为我需要进行子字符串匹配,如 x.Name.Contains("bar"),所以我需要创建一个 Lookup,将所有可能的子字符串作为索引,针对 Name 进行预处理。虽然在预处理阶段会占用大量内存,但实际搜索过程非常快速。 - painiyff
1
@painiyff:很高兴听到这个消息。如果您需要低内存消耗和前缀搜索支持,您可以使用trie或通过SortedDictionary进行二进制搜索。 - Heinzi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接