learning33

I have an array

Flower[] flower = new Flower[10];

Every object contains information. I want to remove flower[5] from the array and decrease flower.Length so it equals 9.

Is it possible to do this


Re: Visual C# General Remove an object from the middle of an array?

Mamush

This is a classic case of using arrays. if you are using Arrays you can't do it do it Automaticaly if your are asking rather you have to loop through the array and shift each item starting form the one you removed to the end. more over in c# since redimentioning is a pain you are better off copying each element execpt the one you removed, which might be annoying provided that you can use Collections which allow you to remove an item from any location and also reset the size for you automaticaly. consider using ArrayLists or Generic lists depending on your requirment.

Hope helps






Re: Visual C# General Remove an object from the middle of an array?

Frank Boyne

Is it possible Yes. Is it desirable Probably not.

The problem is that you can't just take a pair of scissors and 'snip' out the element you want to get rid of. Instead, you have to create a whole new array that is one shorter than the original and then copy all the elements of the old array (except the one you are removing) to the new array. That isn't terribly efficient and doesn't scale well (the bigger the array is the more expensive removing one element becomes).

A common programming trick in these sorts of situations is to mark the 'removed' element in some way and then write all your code to treat specially marked elements as if they had really been removed. In C# a common way to mark a reference is to use the null value. If you set flower[5] to null that is a lot cheaper than copying the whole array (less one). The downside to this approach is that you may have to write lots of code to check for null and handle it as a special case.

Instead of using an array, why don't you use something from System.Collections.Generic

http://msdn2.microsoft.com/en-us/library/system.collections.generic.aspx

For example List<Flower> can be accessed via item (so it looks like an array in that you can use [5]) but also supports RemoveAt()





Re: Visual C# General Remove an object from the middle of an array?

learning33

Frank Boyne wrote:

Is it possible Yes. Is it desirable Probably not.

The problem is that you can't just take a pair of scissors and 'snip' out the element you want to get rid of. Instead, you have to create a whole new array that is one shorter than the original and then copy all the elements of the old array to the new array. That isn't terribly efficient and doesn't scale well (the bigger the array the more expensive removing one element becomes).

A common programming trick in these sorts of situations is to mark the 'removed' element in some way and then write all your code to treat specially marked elements as if they had really been removed. In C# a common way to mark a reference is to use the null value. If you set flower[5] to null that is a lot cheaper than copying the whole array (less one). The downside to this approach is that you may have to write lots of code to check for null and handle it as a special case.

Instead of using an array, why don't you use something from System.Collections.Generic

http://msdn2.microsoft.com/en-us/library/system.collections.generic.aspx

For example List<Flower> can be accessed via item (so it looks like an array in that you can use [5]) but also supports RemoveAt()



I have never used System.Collections.Generic. It sounds interesting though. Since I've learned from you guys that I can't take pair of sciccors I'm going with the null approach. I'll reinitialize the object as emtpy when I don't want to use it anymore.




Re: Visual C# General Remove an object from the middle of an array?

Greg Beech

It's easy enough to remove an item from an array - classes like List as mentioned above do the hard work for you and are generally better to use, but in some circumstances an array is necessary. You can remove an element in a couple of lines of code, all you do is copy the higher index elements down by one, then set the last element to the default value for the array type:

Code Snippet
public void RemoveAt<T>(T[] array, int index)
{
Array.Copy(items, index + 1, items, index, array.Length - index - 1);
items[items.Length - 1] = default(T);
}







Re: Visual C# General Remove an object from the middle of an array?

timvw

I still prefer the dynamically growing List<T>... (And when an array is really needed, i'll call it's ToArray method)





Re: Visual C# General Remove an object from the middle of an array?

JohnWein

We do this in VB all the time.

Code Snippet

Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click

Dim Flower(9) As Flower

RemoveAtI(Flower, 5)

End Sub

Private Sub RemoveAtI(ByVal A() As Flower, ByVal I As Int32)

Dim J, K As Int32

K = A.Length - 2

For J = I To K

A(J) = A(J + 1)

Next

ReDim Preserve A(K)

End Sub

And since C# is an interface to VB for C coders there must be an equivalent in C#:

Code Snippet

private void button1_Click(object sender, EventArgs e)

{

Flower[] Flower = new Flower[10];

RemoveAtI(Flower, 5);

}

private void RemoveAtI(Flower[] A, Int32 I)

{

Int32 J = 0;

Int32 K = 0;

K = A.Length - 1;

for (J = I; J < K; J++)

{

A[J] = A[J + 1];

}

Array.Resize(ref A, K);

}





Re: Visual C# General Remove an object from the middle of an array?

Greg Beech

Looping round to copy the elements will be orders of magnitude slower than using Array.Copy as illustrated a couple of posts previously though.






Re: Visual C# General Remove an object from the middle of an array?

JohnWein

I did this in VB because the timing in the IDE for VB is closer to what it would be in an EXE.

Code Snippet

Private SW As New Stopwatch

Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click

Dim Flower(1999) As String

SW.Reset()

For J As Int32 = 0 To 1999

Flower(J) = J.ToString

Next

SW.Start()

For I As Int32 = 0 To 999

RemoveAtI(Flower, 500000)

Next I

SW.Stop()

Console.WriteLine(CStr(1000 * SW.ElapsedTicks / Stopwatch.Frequency))

End Sub

Private Sub RemoveAtI(ByVal A() As String, ByVal I As Int32)

Dim J, K As Int32

K = A.Length - 2

For J = I To K

A(J) = A(J + 1)

Next

ReDim Preserve A(K)

End Sub

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click

Dim Flower(1999) As String

SW.Reset()

For J As Int32 = 0 To 1999

Flower(J) = J.ToString

Next

SW.Start()

For I As Int32 = 0 To 999

RemoveAt(Flower, 5)

Next I

SW.Stop()

Console.WriteLine(CStr(1000 * SW.ElapsedTicks / Stopwatch.Frequency))

End Sub

Public Sub RemoveAt(ByVal T() As String, ByVal index As Integer)

Array.Copy(T, T, index - 1)

Array.Copy(T, index + 1, T, index, T.Length - index - 1)

Array.Resize(T, T.Length - 1)

End Sub

Button1

6.181463415
7.52199104
6.655015928
6.560423096
6.589295172
6.630666501
6.631433051
6.914728223
7.218699353
6.577905923

Average = 6.74816217 microseconds per iteration

Button2

9.299918367
9.560892982
9.154134893
9.387106023
9.361564958
9.919027875
9.324287208
9.316271777
9.394283723
9.28640667

Average = 9.00389447 microseconds per iteration

It's a matter of personal choice. Database programmers probably prefer lists. Programmers who deal with bitmaps would probably prefer arrays.





Re: Visual C# General Remove an object from the middle of an array?

Jeremy Filburn

John,

What is this all about "And since C# is an interface to VB for C coders there must be an equivalent in C#:"

LINQ was implemented in C# first, then added to VB. If VB was the main focus as the above comment suggest, shouldn't it be the other way around

"the only people who say that VB and C# are the same, or any derivation of the idea, are VB developers"

C# and VB both have their strengths. And as we move forward, I think we will see more separation between the two, but to think that one is an interface to another is a fallacy!

I would like to hear from some MS insiders as to what direction VB is going or what direction they would like to see it go!

Maybe you should post this in the VB forum...




Re: Visual C# General Remove an object from the middle of an array?

JohnWein

Time something in the IDE using VC# and again using equivalent code using VB. Also, Redirect output to a file and time the Release .EXE. But you are totally correctly, it was an off the wall comment. Here is my thinking. When you start a Application in C#, what is the first component you see in the Object Browser VB.NET was introduced as an upgrade to VB6. C# was introduced as a new programming language for C/C+/C++ users to simplify the use of .NET for those users. Which came first, the VB6 upgrade or C# I posted the VB code in this forum because I was answering a post in this forum and because timing in the IDE is more representative of the Release timing in VB. That's the code I used to time the different approaches so that's the code I posted. The C# code has already been posted previously.





Re: Visual C# General Remove an object from the middle of an array?

Greg Beech

You added a superfluous Array.Copy into the method that uses that approach though... The first line isn't needed. It will of course be slower if you copy the whole array unnecessarily each time! Also your Array.Resize isn't doing anything as it's throwing away the reference to the resized array. Comparing purely the element removal code (shown below) I get the results as shown, so the copying way really is a lot faster. Of course, what you'll find if you want to trim the array to size is that it's quicker to copy directly into the new array rather then reshuffle the current one and then resize it.

Removing using loop ...
28.5321179088404
24.2759903842527
28.3820988421713
27.9881940302469
27.0796986767871
25.7468477138854
31.1209944280628
23.1783648480463
23.4689045674799
23.8927014466922
Removing using Array.Copy ...
1.92314945055866
2.3178923578276
1.58232401045384
1.59629226619584
1.40101605092267
1.43845097631124
1.40967636948271
1.4437589134932
1.40436843230075
1.52309860610776

Code Snippet

delegate void Remover(string[] array, int index);

static void Main(string[] args)

{

Console.WriteLine("Removing using loop ...");

for (int i = 0; i < 10; i++)

{

RemoveTest(RemoveAt1<string>);

}

Console.WriteLine("Removing using Array.Copy ...");

for (int i = 0; i < 10; i++)

{

RemoveTest(RemoveAt2<string>);

}

Console.Read();

}

static void RemoveTest(Remover remover)

{

string[] array = new string[1999];

for (int i = 0; i < array.Length; i++)

{

array[i] = i.ToString();

}

Stopwatch timer = Stopwatch.StartNew();

for (int i = 0; i < 999; i++)

{

remover(array, 5);

}

Console.WriteLine(1000D * timer.ElapsedTicks / Stopwatch.Frequency);

}

static void RemoveAt1<T>(T[] array, int index)

{

int limit = array.Length - 2;

for (int i = index; i < limit; i++)

{

array[i] = array[i + 1];

}

array[array.Length - 1] = default(T);

}

static void RemoveAt2<T>(T[] array, int index)

{

Array.Copy(array, index + 1, array, index, array.Length - index - 1);

array[array.Length - 1] = default(T);

}






Re: Visual C# General Remove an object from the middle of an array?

Greg Beech

I got bored so here's a comparison of removing and trimming to size by (1) copying in a loop then resizing the array, vs. (2) copying into a new array using Array.Copy. It's again clear that the second approach is much faster.

Removing using loop ...
134.396690082119
64.3252145174876
30.0739339776424
27.638708271582
49.7239174252594
27.2241304411594
27.3537558544452
23.9837744741301
23.9533236766125
32.8273565495056
Removing using Array.Copy ...
10.8698172533101
6.8880262714954
7.85407083861217
8.35804550578356
7.52972794028291
6.66146116336015
9.16177894117828
6.68353100743251
7.78506765524669
6.64581671692911


Code Snippet

delegate void Remover(ref string[] array, int index);

static void Main(string[] args)
{
Console.WriteLine("Removing using loop ...");
for (int i = 0; i < 10; i++)
{
RemoveTest(RemoveAt1<string>);
}
Console.WriteLine("Removing using Array.Copy ...");
for (int i = 0; i < 10; i++)
{
RemoveTest(RemoveAt2<string>);
}
Console.Read();
}

static void RemoveTest(Remover remover)
{
string[] array = new string[1999];
for (int i = 0; i < array.Length; i++)
{
array[i] = i.ToString();
}

Stopwatch timer = Stopwatch.StartNew();
for (int i = 0; i < 999; i++)
{
remover(ref array, 5);
}
Console.WriteLine(1000D * timer.ElapsedTicks / Stopwatch.Frequency);
}

static void RemoveAt1<T>(ref T[] array, int index)
{
int limit = array.Length - 2;
for (int i = index; i < limit; i++)
{
array[i] = array[i + 1];
}
Array.Resize(ref array, array.Length - 1);
}

static void RemoveAt2<T>(ref T[] array, int index)
{
T[] newArray = new T[array.Length - 1];
Array.Copy(array, 0, newArray, 0, index);
Array.Copy(array, index + 1, newArray, index, newArray.Length - index);
array = newArray;
}







Re: Visual C# General Remove an object from the middle of an array?

JohnWein

Well, most of what I have said in this thread is wrong. Forgive my mad cow disease. That's the nice thing about being old, you can blame your mistakes on senility. All of what you said about my previous code was correct, but you missed a really big error: RemoveAtI(Flower, 500000). Being new to .NET doesn't justify those kinds of coding errors.

There is no need to include resizing the array in the timing as it should be the same both ways. Using Array.Copy vs. loop copy is similar to loading a file into a buffer vs. reading a file line by line.

I compared the corrected console code in both VB and C# on my computer ( an AMD X64 X2 3800 targeted to X86)

Code Snippet

Private Delegate Sub Remover(ByVal arry As String(), ByVal index As Integer)

Sub Main(ByVal args As String())

Console.WriteLine("Removing using loop ...")

For i As Integer = 0 To 9

RemoveTest(AddressOf RemoveAt1(Of String))

Next i

Console.WriteLine("Removing using Array.Copy ...")

For i As Integer = 0 To 9

RemoveTest(addressof RemoveAt2(Of String))

Next i

Console.Read()

End Sub

Private Sub RemoveTest(ByVal remover As Remover)

Dim arry As String() = New String(1999) {}

For i As Integer = 0 To arry.Length - 1

arry(i) = i.ToString()

Next i

Dim timer As Stopwatch = Stopwatch.StartNew()

For i As Integer = 0 To 999

remover(arry, 5)

Next i

Console.WriteLine(1000 * timer.ElapsedTicks / Stopwatch.Frequency)

End Sub

Private Sub RemoveAt1(Of T)(ByVal arry As T(), ByVal index As Integer)

Dim limit As Integer = arry.Length - 2

For i As Integer = index To limit

arry(i) = arry(i + 1)

Next i

End Sub

Private Sub RemoveAt2(Of T)(ByVal arry As T(), ByVal index As Integer)

Array.Copy(arry, index + 1, arry, index, arry.Length - index - 1)

End Sub

Removing using loop ...
27.5802140368342
18.8552926829268
27.1764579392733
18.9000139372822
22.9380826281732
19.3287137879542
27.6850691886511
23.2062414136386
22.9384619213539
23.0611707317073
Removing using Array.Copy ...
1.85574614235938
1.39678397212544
1.23816575410652
1.23817670482827
1.2389780985565
1.23984021901444
5.46309059233449
1.39852215032354
1.23812244897959
1.23723792931807

Code Snippet

delegate void Remover(string[] array, int index);

static void Main(string[] args)

{

Console.WriteLine("Removing using loop ...");

for (int i = 0; i < 10; i++)

{

RemoveTest(RemoveAt1<string>);

}

Console.WriteLine("Removing using Array.Copy ...");

for (int i = 0; i < 10; i++)

{

RemoveTest(RemoveAt2<string>);

}

Console.Read();

}

static void RemoveTest(Remover remover)

{

string[] array = new string[2000];

for (int i = 0; i < array.Length; i++)

{

array[i] = i.ToString();

}

Stopwatch timer = Stopwatch.StartNew();

for (int i = 0; i < 1000; i++)

{

remover(array, 5);

}

Console.WriteLine(1000D * timer.ElapsedTicks / Stopwatch.Frequency);

}

static void RemoveAt1(T[] array, int index)

{

int limit = array.Length - 1;

for (int i = index; i < limit; i++)

{

array[i] = array[i + 1];

}

}

static void RemoveAt2(T[] array, int index)

{

Array.Copy(array, index + 1, array, index, array.Length - index - 1);

}

Code Snippet

Removing using loop ...
18.7465515181682
18.4240233947237
18.1630114484818
18.9259980089597
14.1015181682429
17.9877934295669
17.9235709308113
17.9274081632653
18.0735241413639
18.1009158785465
Removing using Array.Copy ...
1.78155550024888
1.40802339472374
1.23315331010453
1.2328362369338
1.23247287207566
1.23311100049776
1.23292782478845
1.4309412643106
1.23203832752613
1.23212145345943