You could use this version of List which gives you direct access to the underlying array (with .array) when you are not inserting or removing elements. Then it is as fast as an array when accessing the values:
namespace System.Collections.Generic {
using System;
using System.Diagnostics;
using System.Collections.ObjectModel;
using System.Security.Permissions;
// Implements a variable-size List that uses an array of objects to store the
// elements. A List has a capacity, which is the allocated length
// of the internal array. As elements are added to a List, the capacity
// of the List is automatically increased as required by reallocating the
// internal array.
//
[Serializable()]
public class MyList<T> : IList<T>, System.Collections.IList
{
private const int _defaultCapacity = 4;
public T[] _items;
public int _size;
public int _version;
[NonSerialized]
private Object _syncRoot;
static T[] _emptyArray = new T[0];
// Constructs a List. The list is initially empty and has a capacity
// of zero. Upon adding the first element to the list the capacity is
// increased to 16, and then increased in multiples of two as required.
public MyList() {
_items = _emptyArray;
}
// Constructs a List with a given initial capacity. The list is
// initially empty, but will have room for the given number of elements
// before any reallocations are required.
//
public MyList(int capacity) {
_items = new T[capacity];
}
// Constructs a List, copying the contents of the given collection. The
// size and capacity of the new list will both be equal to the size of the
// given collection.
//
public MyList(IEnumerable<T> collection) {
ICollection<T> c = collection as ICollection<T>;
if( c != null) {
int count = c.Count;
_items = new T[count];
c.CopyTo(_items, 0);
_size = count;
}
else {
_size = 0;
_items = new T[_defaultCapacity];
using(IEnumerator<T> en = collection.GetEnumerator()) {
while(en.MoveNext()) {
Add(en.Current);
}
}
}
}
// Gets and sets the capacity of this list. The capacity is the size of
// the internal array used to hold items. When set, the internal
// array of the list is reallocated to the given capacity.
//
public int Capacity {
get { return _items.Length; }
set {
if (value != _items.Length) {
if (value > 0) {
T[] newItems = new T[value];
if (_size > 0) {
Array.Copy(_items, 0, newItems, 0, _size);
}
_items = newItems;
}
else {
_items = _emptyArray;
}
}
}
}
// Read-only property describing how many elements are in the List.
public int Count {
get { return _size; }
}
bool System.Collections.IList.IsFixedSize {
get { return false; }
}
// Is this List read-only?
bool ICollection<T>.IsReadOnly {
get { return false; }
}
bool System.Collections.IList.IsReadOnly {
get { return false; }
}
// Is this List synchronized (thread-safe)?
bool System.Collections.ICollection.IsSynchronized {
get { return false; }
}
// Synchronization root for this object.
Object System.Collections.ICollection.SyncRoot {
get {
if( _syncRoot == null) {
System.Threading.Interlocked.CompareExchange(ref _syncRoot, new Object(), null);
}
return _syncRoot;
}
}
// Sets or Gets the element at the given index.
//
public T this[int index] {
get {
return _items[index];
}
set {
_items[index] = value;
}
}
public T[] array {
get {
return _items;
}
}
private static bool IsCompatibleObject(object value) {
if( (value is T) || ( value == null && !typeof(T).IsValueType) ) {
return true;
}
return false;
}
private static void VerifyValueType(object value) {
}
Object System.Collections.IList.this[int index] {
get {
return this[index];
}
set {
this[index] = (T) value;
}
}
// Adds the given object to the end of this list. The size of the list is
// increased by one. If required, the capacity of the list is doubled
// before adding the new element.
//
public void Add(T item) {
if (_size == _items.Length) EnsureCapacity(_size + 1);
_items[_size++] = item;
_version++;
}
int System.Collections.IList.Add(Object item)
{
VerifyValueType(item);
Add((T) item);
return Count - 1;
}
// Adds the elements of the given collection to the end of this list. If
// required, the capacity of the list is increased to twice the previous
// capacity or the new size, whichever is larger.
//
public void AddRange(IEnumerable<T> collection) {
InsertRange(_size, collection);
}
public ReadOnlyCollection<T> AsReadOnly() {
return new ReadOnlyCollection<T>(this);
}
// Searches a section of the list for a given element using a binary search
// algorithm. Elements of the list are compared to the search value using
// the given IComparer interface. If comparer is null, elements of
// the list are compared to the search value using the IComparable
// interface, which in that case must be implemented by all elements of the
// list and the given search value. This method assumes that the given
// section of the list is already sorted; if this is not the case, the
// result will be incorrect.
//
// The method returns the index of the given value in the list. If the
// list does not contain the given value, the method returns a negative
// integer. The bitwise complement operator (~) can be applied to a
// negative result to produce the index of the first element (if any) that
// is larger than the given search value. This is also the index at which
// the search value should be inserted into the list in order for the list
// to remain sorted.
//
// The method uses the Array.BinarySearch method to perform the
// search.
//
public int BinarySearch(int index, int count, T item, IComparer<T> comparer) {
return Array.BinarySearch<T>(_items, index, count, item, comparer);
}
public int BinarySearch(T item)
{
return BinarySearch(0,Count,item, null);
}
public int BinarySearch(T item, IComparer<T> comparer)
{
return BinarySearch(0,Count,item,comparer);
}
// Clears the contents of List.
public void Clear() {
if (_size > 0)
{
Array.Clear(_items, 0, _size); // Don't need to doc this but we clear the elements so that the gc can reclaim the references.
_size = 0;
}
_version++;
}
// Contains returns true if the specified element is in the List.
// It does a linear, O(n) search. Equality is determined by calling
// item.Equals().
//
public bool Contains(T item) {
if ((Object) item == null) {
for(int i=0; i<_size; i++)
if ((Object) _items *== null)*
if (c.Equals(items*, item)) return true;
_ }*
* return false;*
* }*
* }*
* bool System.Collections.IList.Contains(Object item)*
* {*
* if(IsCompatibleObject(item)) {*
* return Contains((T) item);*
* }*
* return false;*
* }*
* public MyList ConvertAll(Converter<T,TOutput> converter) {*
* MyList list = new MyList(size);
for( int i = 0; i< size; i++) {
list._items = converter(_items);*
* }*
* list.size = size;*
* return list;*
* }*
* // Copies this List into array, which must be of a*
* // compatible array type.*
* //*
* public void CopyTo(T[] array) {*
* CopyTo(array, 0);*
* }*
* // Copies this List into array, which must be of a*
* // compatible array type.*
* //*
* void System.Collections.ICollection.CopyTo(Array array, int arrayIndex) {*
* try {*
* // Array.Copy will check for NULL.*
* Array.Copy(items, 0, array, arrayIndex, size);*
* }*
* catch(ArrayTypeMismatchException e){*
* throw e;*
* }*
* }*
* // Copies a section of this list to the given array at the given index.*
* //*
* // The method uses the Array.Copy method to copy the elements.*
* //*
* public void CopyTo(int index, T[] array, int arrayIndex, int count) {*
* // Delegate rest of error checking to Array.Copy.*
* Array.Copy(items, index, array, arrayIndex, count);*
* }*_
* public void CopyTo(T[] array, int arrayIndex) {*
* // Delegate rest of error checking to Array.Copy.*
* Array.Copy(items, 0, array, arrayIndex, size);*
* }*
* // Ensures that the capacity of this list is at least the given minimum*
* // value. If the currect capacity of the list is less than min, the*
* // capacity is increased to twice the current capacity or to min,*
* // whichever is larger.*
* private void EnsureCapacity(int min) {*
* if (items.Length < min) {
int newCapacity = _items.Length == 0? _defaultCapacity : items.Length * 2;
if (newCapacity < min) newCapacity = min;*
* Capacity = newCapacity;*
* }*
* }*
* public bool Exists(Predicate match) {*
* return FindIndex(match) != -1;*
* }*
* public T Find(Predicate match) {*
* for(int i = 0 ; i < size; i++) {
if(match(_items)) {
return _items;*
* }
}
return default(T);
}*_
* public List FindAll(Predicate match) {*
* List list = new List();*
* for(int i = 0 ; i < size; i++) {
if(match(_items)) {
list.Add(_items);*
* }
}
return list;
}*_
* public int FindIndex(Predicate match) {*
* return FindIndex(0, size, match);*
* }*_
* public int FindIndex(int startIndex, Predicate match) {*
* return FindIndex( startIndex, size - startIndex, match);*
* }*_
* public int FindIndex(int startIndex, int count, Predicate match) {*
* int endIndex = startIndex + count;*
* for( int i = startIndex; i < endIndex; i++) {*
if( match(items*)) return i;*
* }
return -1;
}*_
* public T FindLast(Predicate match) {*
* for(int i = size - 1 ; i >= 0; i–) {
if(match(_items)) {
return _items;*
* }
}
return default(T);
}*_
* public int FindLastIndex(Predicate match) {*
* return FindLastIndex( size - 1, size, match);*
* }*
* public int FindLastIndex(int startIndex, Predicate match) {*
* return FindLastIndex( startIndex, startIndex + 1, match);*
* }*
* public int FindLastIndex(int startIndex, int count, Predicate match) {*
* int endIndex = startIndex - count;*
* for( int i = startIndex; i > endIndex; i–) {*
if( match(items*)) {*
* return i;
}
}
return -1;
}*_
* public void ForEach(Action action) {*
* for(int i = 0 ; i < size; i++) {
action(_items);*
* }
}*_
* // Returns an enumerator for this list with the given*
* // permission for removal of elements. If modifications made to the list*
* // while an enumeration is in progress, the MoveNext and*
* // GetObject methods of the enumerator will throw an exception.*
* //*
* public Enumerator GetEnumerator() {*
* return new Enumerator(this);*
* }*
* /// *
* IEnumerator IEnumerable.GetEnumerator() {*
* return new Enumerator(this);*
* }*
* System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {*
* return new Enumerator(this);*
* }*
* public MyList GetRange(int index, int count) {*
* MyList list = new MyList(count);*
* Array.Copy(items, index, list.items, 0, count);
list.size = count;*
* return list;*
* }*_
* // Returns the index of the first occurrence of a given value in a range of*
* // this list. The list is searched forwards from beginning to end.*
* // The elements of the list are compared to the given value using the*
* // Object.Equals method.*
* //*
* // This method uses the Array.IndexOf method to perform the*
* // search.*
* //*
* public int IndexOf(T item) {*
* return Array.IndexOf(items, item, 0, size);*
* }*
* int System.Collections.IList.IndexOf(Object item)*
* {*
* if(IsCompatibleObject(item)) {*
* return IndexOf((T)item);*
* }*
* return -1;*
* }*
* // Returns the index of the first occurrence of a given value in a range of*
* // this list. The list is searched forwards, starting at index*
* // index and ending at count number of elements. The*
* // elements of the list are compared to the given value using the*
* // Object.Equals method.*
* //*
* // This method uses the Array.IndexOf method to perform the*
* // search.*
* //*
* public int IndexOf(T item, int index) {*
* return Array.IndexOf(items, item, index, size - index);*
* }*
* // Returns the index of the first occurrence of a given value in a range of*
* // this list. The list is searched forwards, starting at index*
* // index and upto count number of elements. The*
* // elements of the list are compared to the given value using the*
* // Object.Equals method.*
* //*
* // This method uses the Array.IndexOf method to perform the*
* // search.*
* //*
* public int IndexOf(T item, int index, int count) {*
* return Array.IndexOf(items, item, index, count);*
* }*_
* // Inserts an element into this list at a given index. The size of the list*
* // is increased by one. If required, the capacity of the list is doubled*
* // before inserting the new element.*
* //*
* public void Insert(int index, T item) {*
* // Note that insertions at the end are legal.*
* if (_size == _items.Length) EnsureCapacity(_size + 1);
if (index < _size) {
Array.Copy(_items, index, items, index + 1, size - index);*
* }*
* _items[index] = item;
size++;
version++;*
* }*
* void System.Collections.IList.Insert(int index, Object item)*
* {*
* VerifyValueType(item);*
* Insert(index, (T) item);*
* }*
* // Inserts the elements of the given collection at a given index. If*
* // required, the capacity of the list is increased to twice the previous*
* // capacity or the new size, whichever is larger. Ranges may be added*
* // to the end of the list by setting index to the List’s size.*
* //*
* public void InsertRange(int index, IEnumerable collection) {*
* ICollection c = collection as ICollection;*
* if( c != null ) { // if collection is ICollection*
* int count = c.Count;*
* if (count > 0) {*
* EnsureCapacity(_size + count);
if (index < _size) {
Array.Copy(_items, index, items, index + count, size - index);*
* }*
* // If we’re inserting a List into itself, we want to be able to deal with that.*
* if (this == c) {*
* // Copy first part of items to insert location*
* Array.Copy(items, 0, items, index, index);
// Copy last part of items back to inserted location*
Array.Copy(items, index+count, items, index2, size-index);
}*
* else {*
* T[] itemsToInsert = new T[count];*
* c.CopyTo(itemsToInsert, 0);_
itemsToInsert.CopyTo(items, index);*
* }_
size += count;*
* }
}
else {
using(IEnumerator en = collection.GetEnumerator()) {
while(en.MoveNext()) {
Insert(index++, en.Current);
}
}
}_
version++;*
* }*_
* // Returns the index of the last occurrence of a given value in a range of*
* // this list. The list is searched backwards, starting at the end*
* // and ending at the first element in the list. The elements of the list*
* // are compared to the given value using the Object.Equals method.*
* //*
* // This method uses the Array.LastIndexOf method to perform the*
* // search.*
* //*
* public int LastIndexOf(T item)*
* {*
* return LastIndexOf(item, size - 1, size);*
* }*
* // Returns the index of the last occurrence of a given value in a range of*
* // this list. The list is searched backwards, starting at index*
* // index and ending at the first element in the list. The*
* // elements of the list are compared to the given value using the*
* // Object.Equals method.*
* //*
* // This method uses the Array.LastIndexOf method to perform the*
* // search.*
* //*
* public int LastIndexOf(T item, int index)*
* {*
* return LastIndexOf(item, index, index + 1);*
* }*
* // Returns the index of the last occurrence of a given value in a range of*
* // this list. The list is searched backwards, starting at index*
* // index and upto count elements. The elements of*
* // the list are compared to the given value using the Object.Equals*
* // method.*
* //*
* // This method uses the Array.LastIndexOf method to perform the*
* // search.*
* //*
* public int LastIndexOf(T item, int index, int count) {*
* if (size == 0) {*
* return -1;
}*_
* return Array.LastIndexOf(items, item, index, count);*
* }*_
* // Removes the element at the given index. The size of the list is*
* // decreased by one.*
* //*
* public bool Remove(T item) {*
* int index = IndexOf(item);*
* if (index >= 0) {*
* RemoveAt(index);*
* return true;*
* }*
* return false;*
* }*
* void System.Collections.IList.Remove(Object item)*
* {*
* if(IsCompatibleObject(item)) {*
* Remove((T) item);*
* }*
* }*
* // This method removes all items which matches the predicate.*
* // The complexity is O(n).*
* public int RemoveAll(Predicate match) {*
* int freeIndex = 0; // the first free slot in items array*
* // Find the first item which needs to be removed.*
* while( freeIndex < _size && !match(_items[freeIndex])) freeIndex++;
if( freeIndex >= _size) return 0;*
* int current = freeIndex + 1;*
* while( current < size) {*
* // Find the first item which needs to be kept._
while( current < _size && match(_items[current])) current++;*
* if( current < size) {*
* // copy item to the free slot._
items[freeIndex++] = items[current++];*
* }*
* }*
* Array.Clear(_items, freeIndex, size - freeIndex);
int result = size - freeIndex;
size = freeIndex;
version++;*
* return result;*
* }*
* // Removes the element at the given index. The size of the list is*
* // decreased by one.*
* //*
* public void RemoveAt(int index) {*
* _size–;
if (index < _size) {
Array.Copy(_items, index + 1, items, index, size - index);*
* }*
* _items[size] = default(T);
version++;*
* }*
* // Removes a range of elements from this list.*
* //*
* public void RemoveRange(int index, int count) {*
* if (count > 0) {*
* int i = _size;
_size -= count;
if (index < _size) {
Array.Copy(items, index + count, items, index, size - index);*
* }*
* Array.Clear(items, size, count);
version++;*
* }*
* }*
* // Reverses the elements in this list.*
* public void Reverse() {*
* Reverse(0, Count);*
* }*
* // Reverses the elements in a range of this list. Following a call to this*
* // method, an element in the range given by index and count*
* // which was previously located at index i will now be located at*
* // index index + (index + count - i - 1).*
* //*
* // This method uses the Array.Reverse method to reverse the*
* // elements.*
* //*
* public void Reverse(int index, int count) {*
* Array.Reverse(items, index, count);
version++;*
* }*
* // Sorts the elements in this list. Uses the default comparer and*
* // Array.Sort.*
* public void Sort()*
* {*
* Sort(0, Count, null);*
* }*
* // Sorts the elements in this list. Uses Array.Sort with the*
* // provided comparer.*
* public void Sort(IComparer comparer)*
* {*
* Sort(0, Count, comparer);*
* }*
* // Sorts the elements in a section of this list. The sort compares the*
* // elements to each other using the given IComparer interface. If*
* // comparer is null, the elements are compared to each other using*
* // the IComparable interface, which in that case must be implemented by all*
* // elements of the list.*
* //*
* // This method uses the Array.Sort method to sort the elements.*
* //*
* public void Sort(int index, int count, IComparer comparer) {*
* Array.Sort(items, index, count, comparer);
version++;*
* }*
* public class ComparisonComparer : IComparer*
* {*
* private readonly Comparison _comparison;*
* public ComparisonComparer(Comparison comparison)*
* {*
* comparison = comparison;*
* }*_
* public int Compare(T x, T y)*
* {*
* return comparison(x, y);*
* }
}*_
* public void Sort(Comparison comparison) {*
* if( size > 0) {*
* IComparer comparer = new ComparisonComparer(comparison);_
Array.Sort(items, 0, size, comparer);*
* }*
* }*
* // ToArray returns a new Object array containing the contents of the List.*
* // This requires copying the List, which is an O(n) operation.*
* public T[] ToArray() {*
* T array = new T[size];
Array.Copy(items, 0, array, 0, size);*
* return array;*
* }*_
* // Sets the capacity of this list to the size of the list. This method can*
* // be used to minimize a list’s memory overhead once it is known that no*
* // new elements will be added to the list. To completely clear a list and*
* // release all memory referenced by the list, execute the following*
* // statements:*
* //*
* // list.Clear();*
* // list.TrimExcess();*
* //*
* public void TrimExcess() {*
int threshold = (int)(((double)items.Length) * 0.9);
* if( size < threshold ) {
Capacity = size;*
* }*
* }*_
* public bool TrueForAll(Predicate match) {*
* for(int i = 0 ; i < size; i++) {
if( !match(_items)) {*
* return false;
}
}
return true;
}*_
* [Serializable()]*
* public struct Enumerator : IEnumerator, System.Collections.IEnumerator*
* {*
* private MyList list;*
* private int index;*
* private int version;*
* private T current;*
* internal Enumerator(MyList list) {*
* this.list = list;*
* index = 0;*
* version = list.version;*
* current = default(T);
}*_
* public void Dispose() {*
* }*
* public bool MoveNext() {*
* MyList localList = list;*
* if (version == localList.version && ((uint)index < (uint)localList.size))*
* {*
* current = localList.items[index];*
* index++;
return true;
}
return MoveNextRare();
}*_
* private bool MoveNextRare()*
* {*
* index = list.size + 1;*
* current = default(T);
return false;
}*_
* public T Current {*
* get {*
* return current;*
* }*
* }*
* Object System.Collections.IEnumerator.Current {*
* get {*
* return Current;*
* }*
* }*
* void System.Collections.IEnumerator.Reset() {*
* index = 0;*
* current = default(T);*
* }*
* }*
* }*
}
List are not slower than array since they are themselves array. So just use a list. The only difference is that they take more space than regular array so that they can add and remove without constantly resizing.
– fafaseRefering to [this answer][1], arrays are much faster than lists. But that is not the question, I would rather want to know, if the resize method from unity undoes the speed advantage from arrays or not. But if you didn't refer to the .Net List, could you please tell me which list meant? Greetings Chillersanim [1]: http://answers.unity3d.com/questions/38479/is-listt-as-fast-to-access-as-a-standard-array.html
– chillersanimOk, I will do some benchmark, althought the access speed for the lists I use gets slower the more items I have. For more informations, read the comment I've written to RudyTheDev. Greetings Chillersanim
– chillersanim