ArrayList problem.

  • Thread starter Thread starter GTi
  • Start date Start date
G

GTi

If I use:

ArrayList TimeScale = new ArrayList();
TimeScale.Capacity = 1000;
TimeScale[20]="test 1"

The last line trow me an error:
Index was out of range. Must be non-negative and less than the size of
the collection.
Parameter name: index

Is there anything I don't get here?
 
ArrayList objects are not arrays - it is (essentially) a collection class;
initially (in general - some ctors allow preloading) they are empty. The
capacity is just the upper limit on what it can contain *without having to
grow*. The Count is the current amount of data. If you call .Add() 5 times,
then you will have 5 items, even if the capacity is 200, and [20] will fail.

Are you sure you mean to use ArrayList? You could create (for example) a
string array sized for 1000 items, and then [20] would work.

Marc
 
GTi said:
If I use:

ArrayList TimeScale = new ArrayList();
TimeScale.Capacity = 1000;
TimeScale[20]="test 1"

The last line trow me an error:
Index was out of range. Must be non-negative and less than the size of
the collection.
Parameter name: index

Is there anything I don't get here?

Yes - the capacity isn't the same as the size. The capacity is how big
the ArrayList can become without having to "grow" by copying all its
data into a bigger backing array.
 
An ArrayList is a Collection. Use the Add method to add an element to it.

--
HTH,

Kevin Spencer
Microsoft MVP
..Net Developer
You can lead a fish to a bicycle,
but it takes a very long time,
and the bicycle has to *want* to change.
 
NOTE:
This sample was just a example. In this samples I should use .add();
But the a value is any value between 0 and maxitems and not all values
in that range is used.
 
(where did the sample go?)

class TimeScale
{
public double TempSP = 0.0;
public double TempER = 0.0;
public double PresureSP = 0.0;
public double PresureER = 0.0;
}


maxitems=1000; // from a calculation
ArrayList TimeScale = new ArrayList(maxitems);

for(int a=0; a<maxitems; a++)
{
TimeScale gts = new GraphTimeScale();
gts.TempSP = somevalue2;
gts.TempER = somevalue3;
gts.PresureSP = somevalue4;
gts.PresureER = somevalue5;
TimeScale[a]=gts;

// NOTE in this sample I should use .add(gts);
but <a> can be any number from 0 to maxitems and not all indexes is
filled.
 
GTi said:
If I use:

ArrayList TimeScale = new ArrayList();
TimeScale.Capacity = 1000;
TimeScale[20]="test 1"
The last line trow me an error:
Index was out of range. Must be non-negative and less than the size
of
the collection.
Parameter name: index
Is there anything I don't get here?
Yes - the capacity isn't the same as the size. The capacity is how big
the ArrayList can become without having to "grow" by copying all its
data into a bigger backing array.

Most of us know that to be true. However, the docs would lead one to believe
it *should* work like the OP expected.

from ms-help://MS.VSCC.2003/MS.MSDNQTR.2003FEB.1033/cpref/html/frlrfSystemCollectionsArrayListClassCapacityTopic.htm

"When the value of Capacity is set explicitly, the internal array is also
reallocated to accommodate the specified capacity."
 
One sample I have about 10000 items in a array.
The short discription is like this:

class TimeScale
{
public double TempSP = 0.0;
public double TempER = 0.0;
public double PresureSP = 0.0;
public double PresureER = 0.0;
public int StatusCode = 0;
}

maxitems=1000; // example
ArrayList TimeScale = new ArrayList(maxitems);
for(int a=1; a<maxitems; a++)
{
GraphTimeScale gts = new GraphTimeScale();
gts.TempSP = somevalue1;
gts.TempER = somevalue2;
gts.PresureSP = somevalue3;
gts.PresureER = somevalue4;
gts.StatusCode = somevalue5;
TimeScale[a] = gts;
}


Is there any other and better way of doing this?
 
chris martin said:
Most of us know that to be true. However, the docs would lead one to believe
it *should* work like the OP expected.

from ms-help:<snip>

"When the value of Capacity is set explicitly, the internal array is also
reallocated to accommodate the specified capacity."

That doesn't suggest that it should have worked. That talks about the
size of the internal array, *not* the logical size of the ArrayList
itself.
 
GTi said:
One sample I have about 10000 items in a array.
The short discription is like this:

class TimeScale
{
public double TempSP = 0.0;
public double TempER = 0.0;
public double PresureSP = 0.0;
public double PresureER = 0.0;
public int StatusCode = 0;
}

maxitems=1000; // example
ArrayList TimeScale = new ArrayList(maxitems);
for(int a=1; a<maxitems; a++)
{
GraphTimeScale gts = new GraphTimeScale();
gts.TempSP = somevalue1;
gts.TempER = somevalue2;
gts.PresureSP = somevalue3;
gts.PresureER = somevalue4;
gts.StatusCode = somevalue5;
TimeScale[a] = gts;
}


Is there any other and better way of doing this?

Yes - call the Add method instead of using the indexer. Note that that
will fill the ArrayList from index 0 rather than index 1 (you know
you're only adding maxitems-1 items in the above, don't you?).
 
// NOTE in this sample I should use .add(gts);
but <a> can be any number from 0 to maxitems and not all indexes is
filled.

In that case I suggest you call Add enough times adding null elements,
then use the indexer to set the specific values you're interested in.
 
One leaps to mind: use an array!

In your example the required size is obviously fixed at 1000 (well, 999
actually but who's counting), and you aren't using any of the "bouns"
features of the ArrayList, so why not just use an array? i.e.
GraphTimeScale[].

This would have less overhead, and would give you better type safety. Note:
if you are using .Net 2.0, even if you can't use GraphTimeScale[] you might
want to consider replacing ArrayList with List<GraphTimeScale>

Marc
 
As another thought: you say not all indexes are filled. How sparse is it?
20%? 80%?

If it is going to have any reasonable amount of emptyness, another option is
to use a HashTable, using the index as the key (and will be unique).
Functionally it would be very similar: access might be *slightly* slower
(due to having to look through the hash buckets), but it should still be
acceptable for most usage. If you are using 2.0 you could use
Dictionary<int, GraphTimeScale> which is the generic, type-safe version.

Marc
 
Marc said:
As another thought: you say not all indexes are filled. How sparse is it?
20%? 80%?

If it is going to have any reasonable amount of emptyness, another option is
to use a HashTable, using the index as the key (and will be unique).
Functionally it would be very similar: access might be *slightly* slower
(due to having to look through the hash buckets), but it should still be
acceptable for most usage. If you are using 2.0 you could use
Dictionary<int, GraphTimeScale> which is the generic, type-safe version.

Marc

It can have as low as 2 items in a 10000 list :|

I think I must redesign my function using HashTable or Dictionary.

Tx Marc
 
How about this then:

public class SomeClass { // class for test harness
public readonly int SomeField;
public SomeClass(int value) { SomeField = value; }
}
public class SparseArray<T> { // impersonates an array, but hashtable
implementation
private Dictionary<int, T> data;
public SparseArray() {
data = new Dictionary<int, T>();
}
public SparseArray(int capacity) {
data = new Dictionary<int, T>(capacity);
}
public IEnumerable<int> Indexes {
get { return data.Keys; }
}
public IEnumerable<T> Values {
get { return data.Values; }
}
public void RemoveAt(int index) {
data.Remove(index);
}
public T this[int index] {
set { data[index] = value; }
get {
T value;
data.TryGetValue(index, out value); // ignore ret val
return value;
}
}
}
static class Program { // test harness
[STAThread]
private static void Main() {
Random rand = new Random();
SparseArray<SomeClass> data = new SparseArray<SomeClass>();
// create a sparse "array" in a dictionary
// note that data is **NOT** the position, rather the **key**
(hashtables do not have a strict position)
for (int i = 0; i < 2000; i += rand.Next(1,500)) { // just to
make it interesting
data = new SomeClass(rand.Next());
}

Console.WriteLine("Using indexer (exhaustive)");
for (int i = 0; i < 2000; i++) {
SomeClass value = data;
if(value != null)
Console.WriteLine("{0}: {1}",i,value.SomeField);
}

Console.WriteLine("\"In use\" indexes only");
foreach (int i in data.Indexes) {
Console.WriteLine("{0}: {1}", i, data.SomeField);
}

Console.WriteLine("Values");
foreach (SomeClass value in data.Values) {
Console.WriteLine(value.SomeField);
}
}

}
 
Honestly, I don't know why you're using an ArrayList. An ArrayList is a
Collection of type object, which means that one must use casting to cast any
element in the ArrayList to the type that it is. In addition, as a
Collection, it is a variable-length list. If you want a fixed sized list of
the same data type, your best bet is to use an array:

GraphTimeScale[] TimeScale = new GraphTimeScale[1000];

--
HTH,

Kevin Spencer
Microsoft MVP
..Net Developer
You can lead a fish to a bicycle,
but it takes a very long time,
and the bicycle has to *want* to change.
 
Back
Top