Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

data type for 2 D data

814 views
Skip to first unread message

Tem

unread,
Apr 7, 2008, 6:59:18 PM4/7/08
to
What would be the best data type for storing objects in a 2D array.
the ideal type would be one like generic List but Lists are only 1D. i don't
think i can have an array of lists.
The size of either the row or column is given while the size of the other
dimension can be dynamically changed.

the data type needs to be optimized for performance, only sequential
add/remove is nessesary.

any suggestions?

Tem

Family Tree Mike

unread,
Apr 7, 2008, 10:56:00 PM4/7/08
to
I just wanted to point out that List<List<object>> is perfectly fine. It may
not apply to your situation where one dimension is fixed.

Tem

unread,
Apr 7, 2008, 11:41:23 PM4/7/08
to
thanks. let me try that.

how is it performance wise?

"Family Tree Mike" <FamilyT...@discussions.microsoft.com> wrote in
message news:D9869840-DB01-4CA6...@microsoft.com...

shahka...@gmail.com

unread,
Apr 8, 2008, 12:03:00 AM4/8/08
to
Pardon me if I do not understand the problem statement
But, wouldn't jagged array work

e.g. Person[][] mydata = new Person[9][];
mydata[0] = new Person[4];
mydata[1] = new Person[n];

HTH
Kalpesh

On Apr 7, 8:41 pm, "Tem" <tem1...@yahoo.com> wrote:
> thanks. let me try that.
>
> how is it performance wise?
>

> "Family Tree Mike" <FamilyTreeM...@discussions.microsoft.com> wrote in
> messagenews:D9869840-DB01-4CA6...@microsoft.com...

Tem

unread,
Apr 8, 2008, 2:20:23 AM4/8/08
to
I need to be able to change the size of the array as needed. can this be
done with jagged array?

<shahka...@gmail.com> wrote in message
news:1fc16e47-9300-4fe4...@e10g2000prf.googlegroups.com...

Peter Duniho

unread,
Apr 8, 2008, 2:43:35 AM4/8/08
to
On Mon, 07 Apr 2008 23:20:23 -0700, Tem <tem...@yahoo.com> wrote:

> I need to be able to change the size of the array as needed. can this be
> done with jagged array?

It can be done as easily as it can be with any array. That is, not
conveniently, but possible.

If you want to be able to easily add and delete elements in the
collections, then using List<T> will be better than an array, just as it
would be for the more usual single-dimension collections.

As far as performance goes, if your requirement is to be able to resize
the collections, the the List<T> class is likely to be faster. Assuming
you allocate and copy a new array any time you have to add an element, the
List<T> will be orders of magnitude faster for any size collection where
the speed of the operation would be noticeable, since most of the time
adding an element to a List<T> doesn't involve copying any data except the
one element.

Likewise, if you're using similarly simple techniques to delete or insert
elements, the cost for an array will on average be twice that as for a
List<T> (again, an array would require allocating and copying an entire
new array, whereas with List<T> it would only have to copy, on average,
half the elements of the collection).

In any case, you should start out using the data structure that most
closely fits your need. In this case, that appears to be List<T>. As
long as it performs acceptably, then that's the right implementation to
use. If it doesn't, then you can consider other solutions that aren't as
closely representative of your actual algorithm in order to get better
performance.

Pete

Tem

unread,
Apr 8, 2008, 3:10:29 AM4/8/08
to
>It can be done as easily as it can be with any array.
could you show me an example of how this is done. adding new element to an
already declared array. not sure how to copy data
im learning c#

List<List<object>> is good but i need to fix the size of one dimension
is there such thing as an array of List<>?


"Peter Duniho" <NpOeS...@nnowslpianmk.com> wrote in message
news:op.t894y...@petes-computer.local...

Marc Gravell

unread,
Apr 8, 2008, 3:49:41 AM4/8/08
to
OK, this is probably overkill - but I got bored on the train ;-p

Basically, to minimise bloat, I've wrapped a List<T> to linearize an
arary - i.e. an array [3, *] would be a list where the first 3 values
are row 0, the next 3 are row 1, etc.

Then 'cos I was still bored, I wrapped this with a custom view so that
you can throw it at a grid (you can edit cells, but not add rows) or
single binding - and added change noification.

It should do most what you need!!!!

Marc

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;

class Program
{
static void Main()
{
Matrix<int> grid = new
Matrix<int>(MatrixOrientation.FixedWidth, 10, 5);
grid[2, 2] = 5;
grid.Add(new int[] {1,2,3,4,5,6,7,8,9,0});
Application.EnableVisualStyles();
Application.Run(new Form
{
Controls = {
// demo list (multi) binding
new DataGridView {
Dock = DockStyle.Fill,
DataSource = grid
},
// demo list (single) binding
new TextBox {
Dock = DockStyle.Bottom,
DataBindings = { {"Text", grid, "Col3"}}
}
},
// demo single row binding
DataBindings = {{"Text", grid.DefaultView[2], "Col2"}}

});
}
}

public static class ClassExt
{
public static void CheckNull<T>(this T value, string paramName)
where T : class
{
if (value == null) throw new ArgumentNullException(paramName);
}
}

public enum MatrixOrientation
{
FixedWidth, FixedHeight
}
public class MatrixChangedEventArgs : EventArgs
{
private readonly int x, y;
public int X { get { return x; } }
public int Y { get { return y; } }
public MatrixChangedEventArgs(int x, int y) {
this.x = x;
this.y = y;
}
}
public class Matrix<T> : IListSource
{
public override string ToString()
{
return string.Format("{0}[{1},{2}]", typeof(T).Name, Width,
Height);
}
public event EventHandler<MatrixChangedEventArgs> ValueChanged;
protected void OnValueChanged(int x, int y)
{
if (ValueChanged != null)
{
ValueChanged(this, new MatrixChangedEventArgs(x, y));
}
}
private readonly int fixedSize;
private readonly MatrixOrientation orientation;
public MatrixOrientation Orientation { get { return orientation; } }
private readonly List<T> list;
public Matrix(MatrixOrientation orientation, int width, int height)
{
switch (orientation)
{
case MatrixOrientation.FixedHeight:
fixedSize = height;
break;
case MatrixOrientation.FixedWidth:
fixedSize = width;
break;
default:
throw new ArgumentOutOfRangeException("orientation");
}
this.orientation = orientation;
CheckDimension(width, orientation ==
MatrixOrientation.FixedWidth, "width");
CheckDimension(height, orientation ==
MatrixOrientation.FixedWidth, "height");
list = new List<T>(width * height);
AddRange(orientation == MatrixOrientation.FixedWidth ? height :
width);
}
public void TrimExcess()
{
list.TrimExcess();
}
private void CheckDimension(int size, bool disallowEqual, string
paramName)
{
if (size < 0) throw new ArgumentOutOfRangeException(paramName,
"Dimension cannot be negative");
if (size == 0 && disallowEqual) throw new
ArgumentOutOfRangeException(paramName, "Dimension cannot be zero");
}
public Matrix(MatrixOrientation orientation, int fixedSize)
: this(orientation,
orientation == MatrixOrientation.FixedWidth ? fixedSize : 0,
orientation == MatrixOrientation.FixedHeight ? fixedSize : 0)
{
}

public void Clear()
{
list.Clear();
}
private int Linearize(int x, int y)
{
if (orientation == MatrixOrientation.FixedWidth)
{
if (x < 0 || y < 0 || x >= fixedSize) throw new
ArgumentOutOfRangeException();
return (y * fixedSize) + x;
}
else
{
if (y < 0 || y < 0 || y >= fixedSize) throw new
ArgumentOutOfRangeException();
return (x * fixedSize) + y;
}
}
public T this[int x, int y]
{
get
{
return list[Linearize(x, y)];
}
set
{
list[Linearize(x, y)] = value;
OnValueChanged(x, y);
}
}
public void Add() { AddRange(1); }
public void Add(T[] values)
{
values.CheckNull("values");
if (values.Length != fixedSize) throw new
ArgumentException("Array must be the same size as the fixed dimension",
"values");
list.AddRange(values);
}
public void AddRange(int count) {
CheckDimension(count, false, "count");
count *= fixedSize;
while (count-- > 0)
{
list.Add(default(T));
}
}
public void Remove() { RemoveRange(1); }
public void RemoveRange(int count)
{
CheckDimension(count, false, "count");
count *= fixedSize;
list.RemoveRange(list.Count - count, count);
}
public int FixedSize { get { return fixedSize; } }
public int DynamicSize { get { return list.Count / fixedSize; } }
public int Width
{
get
{
return orientation == MatrixOrientation.FixedWidth
? FixedSize : DynamicSize;
}
}
public int Height
{
get
{
return orientation == MatrixOrientation.FixedHeight
? FixedSize : DynamicSize;
}
}

#region IListSource Members

bool IListSource.ContainsListCollection
{
get { return false; }
}

System.Collections.IList IListSource.GetList()
{
return DefaultView;
}

#endregion

private MatrixView<T> defaultView;
public MatrixView<T> DefaultView {
get {
if(defaultView == null) {
defaultView = new MatrixView<T>(this, false);
}
return defaultView;
}
}
}

public class MatrixView<T> : ITypedList, IList<MatrixViewRow<T>>, IList,
IBindingList
{
private readonly Matrix<T> parent;
private readonly bool transposed;

public MatrixView<T> Transpose()
{
return new MatrixView<T>(parent, !transposed);
}

internal MatrixView(Matrix<T> parent, bool transposed)
{
parent.CheckNull("parent");
this.parent = parent;
this.transposed = transposed;
}

public PropertyDescriptorCollection GetColumns()
{
int width = Width;
List<PropertyDescriptor> props = new
List<PropertyDescriptor>(width);
for (int i = 0; i < width; i++)
{
props.Add(new MatrixViewCol<T>(this, i));
}
return new PropertyDescriptorCollection(props.ToArray(), true);
}
PropertyDescriptorCollection
ITypedList.GetItemProperties(PropertyDescriptor[] listAccessors)
{
if (listAccessors != null && listAccessors.Length != 0)
{
throw new NotSupportedException();
}
return GetColumns();
}
string ITypedList.GetListName(PropertyDescriptor[] listAccessors)
{
return "";
}

public void Clear()
{
parent.Clear();
}
public int IndexOf(MatrixViewRow<T> slice)
{
slice.CheckNull("slice");
return slice.Index;
}
void IList<MatrixViewRow<T>>.Insert(int index, MatrixViewRow<T> slice)
{
throw new NotSupportedException();
}
void IList<MatrixViewRow<T>>.RemoveAt(int index)
{
throw new NotSupportedException();
}
bool ICollection<MatrixViewRow<T>>.Contains(MatrixViewRow<T> slice)
{
if (slice == null) return false;
return slice.Index >= 0 && slice.Index < Height;
}
public int Width
{
get { return transposed ? parent.Height : parent.Width; }
}
public int Height
{
get { return transposed ? parent.Width: parent.Height; }
}
public MatrixViewRow<T> this[int index]
{
get { return new MatrixViewRow<T>(this, index); }
set { throw new NotSupportedException(); }
}
void ICollection<MatrixViewRow<T>>.Add(MatrixViewRow<T> slice)
{
throw new NotSupportedException();
}
bool ICollection<MatrixViewRow<T>>.Remove(MatrixViewRow<T> slice)
{
throw new NotSupportedException();
}
public int Count { get { return Height; } }
bool ICollection<MatrixViewRow<T>>.IsReadOnly { get { return false; } }
bool IList.IsReadOnly { get { return ThisList.IsReadOnly; } }
bool IList.IsFixedSize { get { return true; } }

public IEnumerator<MatrixViewRow<T>> GetEnumerator()
{
for (int i = 0; i < Height; i++)
{
yield return this[i];
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}

int IList.Add(object obj)
{
MatrixViewRow<T> slice = (MatrixViewRow<T>)obj;
ThisList.Add(slice);
return slice.Index;
}
bool IList.Contains(object obj)
{
return ThisList.Contains((MatrixViewRow<T>)obj);
}
int IList.IndexOf(object obj)
{
return IndexOf((MatrixViewRow<T>)obj);
}
void IList.Remove(object obj)
{
ThisList.Remove((MatrixViewRow<T>)obj);
}
private IList<MatrixViewRow<T>> ThisList { get { return this; } }
void IList.Insert(int index, object obj)
{
ThisList.Insert(index, (MatrixViewRow<T>)obj);
}
void IList.RemoveAt(int index)
{
ThisList.RemoveAt(index);
}
object IList.this[int index]
{
get { return this[index]; }
set { this[index] = (MatrixViewRow<T>)value; }
}
object ICollection.SyncRoot
{
get { return parent; }
}
bool ICollection.IsSynchronized
{
get { return false; }
}
void ICollection.CopyTo(Array values, int index)
{
for (int i = 0; i < Height; i++)
{
values.SetValue(this[i], i + index);
}
}

void ICollection<MatrixViewRow<T>>.CopyTo(MatrixViewRow<T>[]
values, int index)
{
for (int i = 0; i < Height; i++)
{
values[i + index] = this[i];
}
}
public bool IsTransposed { get { return transposed; } }
public string RowName(int index)
{
return (IsTransposed ? "Col" : "Row") + index.ToString();
}
public string ColName(int index)
{
return (IsTransposed ? "Row" : "Col") + index.ToString();
}

public T this[int colIndex, int rowIndex]
{
get { return IsTransposed ? parent[rowIndex, colIndex] :
parent[colIndex, rowIndex]; }
set
{
if (IsTransposed)
{
parent[rowIndex, colIndex] = value;
}
else
{
parent[colIndex, rowIndex] = value;
}
}
}

bool IBindingList.AllowNew { get { return false; } }
bool IBindingList.AllowRemove { get { return false; } }
bool IBindingList.AllowEdit { get { return true; } }
object IBindingList.AddNew()
{
throw new NotSupportedException();
}
void IBindingList.AddIndex(PropertyDescriptor property) { }
void IBindingList.RemoveIndex(PropertyDescriptor property) { }
bool IBindingList.SupportsSorting { get { return false; } }
void IBindingList.ApplySort(PropertyDescriptor property,
ListSortDirection direction)
{
throw new NotSupportedException();
}
PropertyDescriptor IBindingList.SortProperty { get { return null; } }
ListSortDirection IBindingList.SortDirection { get { return
ListSortDirection.Ascending; } }
bool IBindingList.IsSorted { get { return false; } }
void IBindingList.RemoveSort() { }
bool IBindingList.SupportsSearching { get { return false; } }
int IBindingList.Find(PropertyDescriptor property, object obj)
{
throw new NotSupportedException();
}
bool IBindingList.SupportsChangeNotification { get { return true; } }
private ListChangedEventHandler listChanged;
public event ListChangedEventHandler ListChanged
{
add
{
bool first = listChanged == null;
listChanged += value;
if (first && listChanged != null) parent.ValueChanged +=
ListChangedHandler;
}
remove {
listChanged -= value;
if (listChanged == null) parent.ValueChanged -=
ListChangedHandler;
}
}
private void OnListChanged(int index) {
if(listChanged != null) {
listChanged(this, new
ListChangedEventArgs(ListChangedType.ItemChanged, index));
}
}
private void OnRowChanged(int index) {
EventHandler handler;
if (rowHandlers != null && rowHandlers.TryGetValue(index, out
handler))
{
handler(this, EventArgs.Empty);
}
}
private void ListChangedHandler(object sender,
MatrixChangedEventArgs args)
{
int index = IsTransposed ? args.X : args.Y;
OnListChanged(index);
}
private void RowChangedHandler(object sender,
MatrixChangedEventArgs args)
{
int index = IsTransposed ? args.X : args.Y;
OnRowChanged(index);
}
internal void AddRowHandler(int index, EventHandler handler)
{
if (handler == null) return;
if (rowHandlers == null)
{
rowHandlers = new Dictionary<int, EventHandler>();
parent.ValueChanged += RowChangedHandler;
}
EventHandler value;
rowHandlers.TryGetValue(index, out value);
value += handler;
rowHandlers[index] = value;
}
internal void RemoveRowHandler(int index, EventHandler handler)
{
if (handler == null || rowHandlers == null) return;
EventHandler value;
if (rowHandlers.TryGetValue(index, out value))
{
value -= handler;
if (value == null)
{
rowHandlers.Remove(index);
if (rowHandlers.Count == 0)
{
rowHandlers = null;
parent.ValueChanged -= RowChangedHandler;
}
}
else
{
rowHandlers[index] = value;
}
}
}
private Dictionary<int, EventHandler> rowHandlers;
}
public class MatrixViewRow<T> : ICustomTypeDescriptor
{
private readonly int index;
public int Index { get { return index; } }
private readonly MatrixView<T> parent;
internal MatrixViewRow(MatrixView<T> parent, int index)
{
if (index < 0) throw new ArgumentOutOfRangeException("index");
parent.CheckNull("parent");
this.index = index;
this.parent = parent;
}
public override string ToString()
{
return parent.RowName(index);
}

#region ICustomTypeDescriptor Members

private static Type RowType { get { return
typeof(MatrixViewRow<T>); } }
AttributeCollection ICustomTypeDescriptor.GetAttributes()
{
return TypeDescriptor.GetAttributes(RowType);
}

string ICustomTypeDescriptor.GetClassName()
{
return TypeDescriptor.GetClassName(RowType);
}

string ICustomTypeDescriptor.GetComponentName()
{
return TypeDescriptor.GetComponentName(RowType);
}

TypeConverter ICustomTypeDescriptor.GetConverter()
{
return TypeDescriptor.GetConverter(RowType);
}

EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
{
return TypeDescriptor.GetDefaultEvent(RowType);
}

PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
{
return TypeDescriptor.GetDefaultProperty(RowType);
}

object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
{
return TypeDescriptor.GetEditor(RowType, editorBaseType);
}

EventDescriptorCollection
ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
{
return TypeDescriptor.GetEvents(RowType, attributes);
}

EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
{
return TypeDescriptor.GetEvents(RowType);
}

PropertyDescriptorCollection
ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
{
return ThisDesc.GetProperties();
}
private ICustomTypeDescriptor ThisDesc { get { return this; } }

PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
{
return parent.GetColumns();
}

object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
{
return this;
}

#endregion
}
internal class MatrixViewCol<T> : PropertyDescriptor
{
public override string ToString()
{
return Name;
}
private static readonly Attribute[] fixedAttribs = new Attribute[0];
private readonly MatrixView<T> parent;
private int index;
public MatrixViewCol(MatrixView<T> parent, int index) : base(parent
== null ? "None" : parent.ColName(index), fixedAttribs)
{
parent.CheckNull("parent");
this.parent = parent;
this.index = index;
}
public override Type ComponentType
{
get { return typeof(MatrixViewRow<T>); }
}
public override bool IsReadOnly
{
get { return false; }
}
public override Type PropertyType
{
get { return typeof(T); }
}
public override bool CanResetValue(object component)
{
return true;
}
public override void ResetValue(object component)
{
SetValue(component, default(T));
}
private MatrixViewRow<T> Row(object component)
{
return ((MatrixViewRow<T>)component);
}
public override void SetValue(object component, object value)
{
parent[index, Row(component).Index] = (T)value;
}
public override object GetValue(object component)
{
return parent[index, Row(component).Index];
}
public override bool ShouldSerializeValue(object component)
{
return
!EqualityComparer<T>.Default.Equals((T)GetValue(component), default(T));
}
protected override object GetInvocationTarget(Type type, object
instance)
{
return base.GetInvocationTarget(type, instance);
}
public override bool SupportsChangeEvents
{
get { return true; }
}
public override void AddValueChanged(object component, EventHandler
handler)
{
parent.AddRowHandler(Row(component).Index, handler);
}
public override void RemoveValueChanged(object component,
EventHandler handler)
{
parent.RemoveRowHandler(Row(component).Index, handler);
}
}

Family Tree Mike

unread,
Apr 8, 2008, 8:23:00 AM4/8/08
to
You can use this (as an example):

private List<string> [ ] arrListString = new List<string> [15];

Make sure however that you initialize each array element to a new
List<string>:

for (int idx = 0; idx < 15; ++idx)
arrListString[idx] = new List<string>();

Marc Gravell

unread,
Apr 8, 2008, 8:36:44 AM4/8/08
to
That is an array of lists, and is a real pain to resize; you can't
change the array, and you'd need to change every list individually. If
you went down this route, a list of arrays (List<T[]>) would be a better
option - at least then you can just add a new T[] as a new row; it is
still jagged, however.

The linearized Matrix<T> I posted earlier handles all this in a single
list, and allows you to have either axis pinned. You could probably
loser all the ITypedList stuff without too much pain, though ;-p

Marc

Janos

unread,
Apr 8, 2008, 8:41:57 AM4/8/08
to
Cool, man !

Thanks for sharing it,

Family Tree Mike

unread,
Apr 8, 2008, 9:33:01 AM4/8/08
to
Agreed. I posted a response to what the poster had asked, I think, before I
saw your other post. I wanted the poster to see what was possible. I liked
(and prefered) your solution!

Tem

unread,
Apr 8, 2008, 3:46:20 PM4/8/08
to
wow thanks for sharing!

Does anyone know how to limit the capacity of a regular List<>?

"Marc Gravell" <marc.g...@gmail.com> wrote in message
news:%23GRr1UX...@TK2MSFTNGP02.phx.gbl...

axx3an...@gmail.com

unread,
Aug 22, 2012, 12:56:09 PM8/22/12
to
On Monday, April 7, 2008 3:59:18 PM UTC-7, Tem wrote:
> What would be the best data type for storing objects in a 2D array. the ideal type would be one like generic List but Lists are only 1D. i don't think i can have an array of lists. The size of either the row or column is given while the size of the other dimension can be dynamically changed.the data type needs to be optimized for performance, only sequential add/remove is nessesary.any suggestions?Tem

That must have been a long train ride.
0 new messages