How and when to abandon the use of arrays in C#?我总是被告知,将元素添加到数组的过程如下:
如果是这样,那么由于内存和CPU使用率的原因,禁止在需要大量元素活动的情况下使用数组,对吗? 如果真是这样,当添加大量元素时,您是否不应该尽量避免使用数组? 您应该改用iStringMap吗? 如果是这样,如果您需要两个以上的维并且需要添加很多元素添加,会发生什么情况。 您只是受到性能影响还是应该使用其他方法?
将通用 这真的取决于您所说的"添加"。 如果你的意思是:
然后,不,这不会创建新的数组,并且实际上是更改.NET中任何IList的最快方法。
但是,如果您使用的是ArrayList,List,Collection等,则调用" Add"方法可能会创建一个新数组-但他们很聪明,它们不仅会按1个元素调整大小,以几何方式增长,因此,如果您不时地一次添加大量值,则必须分配一个新数组。即使这样,如果您知道要添加的元素数(
如果要大量添加/删除元素,只需使用列表即可。如果是多维的,则始终可以使用List 另一方面,如果遍历列表主要是在做列表,则效率不如数组,因为数组全部位于CPU缓存中的一个位置,列表中的对象分散在整个位置。 如果要使用数组进行有效读取,但是要经常"添加"元素,则有两个主要选择: 1)将其生成为一个列表(或列表列表),然后使用ToArray()将其转换为有效的数组结构。 2)分配数组,使其大于所需的大小,然后将对象放入预分配的单元格中。如果最终需要的元素比预先分配的更多,则可以在数组填满时重新分配数组,每次增加一倍。这样就可以为O(log n)调整大小,而不是像重新分配一次添加数组那样的O(n)。请注意,这几乎就是StringBuilder的工作方式,从而为您提供了一种更快速地连续追加到字符串的方法。
通常,我更喜欢避免使用数组。只需使用List < T >。它在内部使用动态大小的数组,并且对于大多数用法而言足够快。如果使用多维数组,则必须使用List 如果您需要0.1%的使用速度,那么在尝试对其进行优化之前,请确保列表访问确实是问题所在。
首先,当数组的语义与您的意图不符时-需要动态增长的集合吗?不允许重复的套装?必须保持不变的集合吗?在所有情况下都避免使用数组。那是99%的情况。仅说明显而易见的基本要点。 其次,当您不为绝对的性能关键性进行编码时-大约是95%的情况。数组的性能略佳,尤其是在迭代中。几乎总是没有关系。
当您不被 当您不编写旧版代码或不处理互操作时 简而言之,实际上很少需要数组非常罕见。我还要补充一下为什么可以避免这种情况? 避免数组imo的最大原因是概念上的。数组离实现更近,而离抽象更远。与违反高级语言精神的做法相比,数组所传达的作用更多。考虑到数组更接近金属,它们是特殊类型的(尽管内部数组是一类),这并不奇怪。并不是教学论,而是数组确实确实转换成非常很少需要的语义。最有用和最常见的语义是具有任何条目的集合,具有不同项目的集合,键值映射等的集合,这些集合具有可加,只读,不可变,遵守顺序的变体的任意组合。考虑一下,您可能需要一个可添加的集合,或者是具有预定义项的只读集合,而无需进行进一步修改,但是您的逻辑看起来像"我想要一个可动态添加的集合,但是只有固定数量的集合,它们也应该可以修改""?我会说非常罕见。 Array是在前泛型时代设计的,它通过大量的运行时hack模仿通用性,并且会在这里和那里展示出它的怪异之处。我发现的一些收获: 破碎的协方差。
数组可以为您提供对struct!的引用。这不同于其他任何地方。一个样品:
对于类型和结构,运行时实现的方法(如
最常用的替代方法是
通常,如果您必须具有BEST索引查找性能,则最好先构建一个List,然后将其转换为数组,这样一开始要付出一点代价,但要避免以后再使用。如果问题在于您将不断添加新数据并删除旧数据,则为方便起见,可能需要使用ArrayList或List,但请记住,它们只是特殊情况的Arrays。当他们"增长"时,他们分配一个全新的数组并将所有内容复制到其中,这非常慢。
ArrayList只是一个需要时增长的Array。 请记住,列表不是链接列表也很重要。这只是一个类型化的ArrayList。列表文档确实指出在大多数情况下它的性能更好,但是没有说明原因。 最好的办法是选择一个适合您问题的数据结构。这取决于很多事情,因此您可能需要浏览System.Collections.Generic命名空间。 在这种情况下,我想说的是,如果您能拿出一个不错的键值,Dictionary将是您的最佳选择。它具有插入和删除接近O(1)的功能。但是,即使使用了Dictionary,也必须注意不要让它调整其内部数组的大小(O(n)操作)。最好通过在构造函数中指定更大的-然后您期望使用的初始容量为它们留出很多空间。 -里克 ArrayList和List在需要时将数组增加一个以上(我认为是通过将大小增加一倍,但我没有检查源)。当您构建动态大小的数组时,它们通常是最佳选择。 当您的基准测试表明数组调整大小严重降低了应用程序的速度时(请记住,过早的优化是万恶之源),您可以评估编写具有调整大小行为的自定义数组类。 调整数组大小时,必须分配新的数组,然后复制内容。如果仅修改数组的内容,则仅是内存分配。 因此,当您不知道数组的大小或大小可能更改时,请勿使用数组。但是,如果您有固定长度的数组,则它们是按索引检索元素的简便方法。
如果您要进行大量添加,并且您将不会进行随机访问(例如 如果我认为我将在整个生命周期中向集合中添加很多项目,那么我将使用列表。如果我肯定知道声明时集合的大小,那么我将使用数组。 另一个我通常在List上使用数组的时间是当我需要将集合作为对象的属性返回时-我不希望调用者通过List的Add方法添加该集合的项目,而是希望他们将项目添加到集合中通过我对象的界面。在这种情况下,我将使用内部List并调用ToArray并返回一个数组。
对于各种阵列类型的效率,此论坛帖子对您可能有用或可能不有用: 您是对的,数组非常适合查找。然而,对阵列尺寸的修改是昂贵的。 在修改数组大小的情况下,应使用支持增量大小调整的容器。您可以使用ArrayList来设置初始大小,并且可以连续检查大小与容量的关系,然后将容量增加一大块以限制调整大小的次数。 或者,您可以只使用链接列表。然后,但是查找起来很慢... 数组非常适合很少的写入和多次读取,尤其是具有迭代性质的读取-对于其他任何事情,都使用许多其他数据结构之一。 标准数组应定义一个长度,以保留其在连续块中需要的所有内存。向数组添加一个项目会将其放入已保留的内存块中。 您可以做的最好的事情就是尽可能分配所需的内存。这将防止.NET进行额外的调用来获取堆上的内存。否则,有意义的是将五个或任何数量的块分配给您的应用程序。 这是一条规则,您可以真正应用于任何事物。 |