我想知道,.NET中的集合实现有什么不同。
例如,我经常使用List<int>
等来存储项目列表。但是我只需要一个容器用于物品,我想我不需要List
具有的所有功能。我只需要一个具有 put 方法的容器,并使客户端代码能够迭代容器。
是否有更快,更轻量级的集合实现在.NET中实现IEnumerable<T>
?
答案 0 :(得分:7)
实现IEnumerable<T>
的最轻量级容器是一个类型化数组。它没有Add
方法(因此不像列表那样动态调整大小)但是如果你知道前面想要多少个元素,你可以定义数组并在给定位置插入元素。
var myArray = new int[10];
myArray[0] = 123;
myArray[1] = 234;
答案 1 :(得分:4)
如果你只需要添加和迭代,我会相信链表是最轻量级的。我没有看过Stack的实现,因此很容易创建一个不占用太多空间的实现。这是一个相当天真的解决方案,可以针对大小进行优化。我的观点是,实施轻量级集合很简单
public class Stack<T>{
readonly T _head;
readonly Stack<T> _tail;
public Stack(T head,Stack<T> tail){
_head = head;
_tail = tail;
}
public Stack<T> Push(T element){
return new Stack<T>(element,this);
}
public IEnumerator<T> GetEnumerator(){
yield return _head;
var current = _tail;
while(_tail != null){
yield return current._head;
current = current._tail;
}
}
}
Performancewise这将比使用预分配数组的实现慢,因为分配给元素比新对象更快并且取决于例如内部数组的填充方式。 list这实际上可能会占用更多的空间,但是每次只使用一个元素新建一个新数组时,可以通过新的数组来交换开销以获得性能,但这在性能方面具有显着的开销。您也可以选择在两者之间取得平衡,在大多数情况下,您可以为大量新元素提供足够的空间来提供内存,但在大多数情况下会提高性能。
public class Stack<T>{
T[] _heads;
T[] _tail;
int _next;
public Stack(T head,T[] tail){
_heads = new T[tail.length];
_next = _heads.Length -2;
_heads[_heads.Length -1] = head;
_tail = tail;
}
public void Push(T element){
if(_next < 0){
var length = _heads.Length;
var _new = new T[length * 2];
_heads = new T[length * 2];
_next = length * 2-1;
Array.Copy(_heads,_new,length);
Array.Copy(_tails,0,_new,length,length);
_tails = _new;
} else{
_heads[_next--] = element;
}
}
public IEnumerator<T> GetEnumerator(){
yield return _head;
var current = _tail;
while(_tail != null){
yield return current._head;
current = current._tail;
}
}
}
并且你基本上回到了像List这样的集合的平衡。它建立在一个内部阵列上,这个阵列通常太大而不能高速添加而不会浪费太多内存。
与所有优化问题一样,它实际上取决于您希望优化的内容。如果你愿意牺牲性能,你通常可以优化记忆,反之亦然
答案 2 :(得分:2)
你究竟在收藏中存放了什么?如果是类型(T
),那么List<T>
是最好的选择。
对于非泛型类型,请考虑使用HashSet
,它们可以在某些情况下显着提高性能。
AS @RuneFS说,因为你要求迭代并放。迭代HashSet与迭代List是相同的(ish)但是将对象添加到HashSet比将其添加到列表更慢(比较哈希)并且功能也不相等(哈希集中的不同哈希)。