Sign in to follow this  

[.net] Assigning values to Array

This topic is 4349 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I want to do something like this:
foreach(Element e in someArray)
  e = new e(...);

However, this gives me an error because you can't assign to a variable you are foreach'ing over. The reason I can't use the standard for-loops is because I don't know the dimensions or the rank of the array. Ultimately, what I want this for is to make an array of the same dimensions as the one I already have, but replace all the elements with element.Name (the array consists of elements of type IRecordable, which has a Name property). Maybe there's already a library function that does this? I couldn't find one. Thank you.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
The reason I can't use the standard for-loops is because I don't know the dimensions or the rank of the array


How is this possible? Arrays have "Length" and "Rank" properties..

Share this post


Link to post
Share on other sites
Right, but it could be something like...

IRecordable[][,,][][,][,,,,,,,,]

I mean I guess it's possible, but is there an easier way of doing it?

Edit: Another problem is outlined in my other post on this forum about te Array's rank. Basically, I can find out the number of commas, but not brackets (so to speak), as that is what Array.Rank returns.

Share this post


Link to post
Share on other sites
I see what you mean. Not only do you have a multidimensional array, the elements within that array are themselves multidimensional arrays. So you have two problems: You need to initialize each array-of-arrays with nested arrays until there is no longer any nesting, at which point you need to initialize the array with new reference types.

Are you writing a generic container class?


void InitializeArray(Array array)
{
int[] indices = new int[array.Rank];
for (int r=0; r<array.Rank; ++r)
indices[r] = array.GetLength(r);

while (indexes[0] >= 0)
{
// use reflection to create an instance of array.GetType().GetElementType()
// but I can't quickly find out how I did this before.
array.SetValue(instance, indices);

if (array.GetType().GetElementType().GetArrayRank() > 0)
{
InitializeArray(instance as Array);
}

// adjust the multidimensional indices.
for (int r=array.Rank-1; r>=0; --r)
{
if (--indices[r] != 0)
break;
}
}
}




Array.GetType().GetElementType() returns the inner array's type for each level of nesting.

Array.Rank obviously returns the rank, like everyone reading this thread knows by now.

Array.GetLength(int rank) returns the length of a particular rank in a multidimensional array.

The ultimate trick is to be able to create the nested array instances. You have to use reflection to do this. I forgot what the "create instance given a System.Type" function is, but I'm sure someone else will know.

Share this post


Link to post
Share on other sites
Thanks. That really helps. However, the problem is not initializing the array. The thing is, the array I'm creating will be the same exact dimensions as the old one (I'm basically replacing someClassInstance with someClassInstance.someMember). So I can clone the original array (since Arrays are not generic and have no specific type). Some the array is initialized fine, I just have to map the elements correctly. But thanks anyway, I'll give it another go, but I'd appreciate more responses.

Share this post


Link to post
Share on other sites
Quote:
Original post by Shinkage
I don't know about C#, but would something like..
for each(Element ^%e in someArray)
e = gcnew e(...);
Work in C++/CLI? Not something I've tried.


If you look at my initial post, that is what I tried to do, but it doesn't work because you can't change values you are foreach'ing over. Also, what does % mean?

Share this post


Link to post
Share on other sites
I just revisited the documentation of Array, and there is a method ConvertAll<In,Out> (...), which seems to do exactly what I want, except it only takes in one-dimensional arrays. If I understand correctly, a one dimensional array is one without commas, but could have multiple parentheses. Can anyone think of a way to use this method to do what I want or would you recommend starting from scratch?

BTW, I am planning to post the code when and if I come up with a solution.

Share this post


Link to post
Share on other sites
Quote:
Original post by yaroslavd
If you look at my initial post, that is what I tried to do, but it doesn't work because you can't change values you are foreach'ing over. Also, what does % mean?


No, what you originally tried to do is in C++/CLI equivalently written thus...
for each(Element ^e in someArray)
e = gcnew e(...);
The % is called a "tracking reference" in C++/CLI and is roughly equivalent to a garbage collected version of the standard C++ reference (&). Mind, this functionality is only available in Visual Studio 2005 since it's part of C++/CLI and not old style Managed C++.

That being said, I booted it up and tried it out, and it does in fact work. The code I originally suggested ( for each(Element ^%... ) will actually set the values within the array. Sorry, but I don't think C# has any equivalent functionality, at least that I know of.

Share this post


Link to post
Share on other sites
Ok, I re-read the original post and have a bit better understanding:

- You have an array which can potentially have any number of dimensions and any number of nested arrays.
- The most nested array contains a known type (IRecordable in this case).
- You want to create a second array that has the same dimensions and nested array configuration, but the most nested type is different, and is initialized based on the source array's element at that position.


One thing I'm unclear on: Do you already have your destination array created, or does the desired function need to create it from scratch based on the source array?

If your destination array is already created, you could modify my function above to take both the source and destination array. It could iterate through them in parallel with slight modifications. You would have to add a condition to detect when you reached the innermost nested array and do your "destination_element = source_element.Name" conversion.


And to answer your question about multidimensional and one-dimensional arrays, for any multidimensional array, you can convert it to a one-dimensional array like so:


// mutlidimensional form
int[,] array = new int[dimension1, dimension2, ... , dimensionN];
array[index1, index2, ... , indexN] = 0;

// one-dimensional form
int[] array = new int[dimension1 * dimension2 * ... * dimensionN];
array[index1 + (index2 * dimension1) + (index3 * dimension2 * dimension1) + ...];

or

array[index1 + dimension1*(index2 + dimension2*(index3 ... ))];


The downside is that you have to keep track of the dimension1 ... dimensionN values somewhere.

Share this post


Link to post
Share on other sites
The problem is that I need the destination array to have the exact same dimensions as the source array.

Basically, IRecordable is an interface which my classes can inherit to be recorded (serialized) by my Recorder class. If an IRecordable member is encountered, its Name member (which is a string and represents the location of the object) is recorded. But now I want to extend that to arrays and then later ICollection<IRecordable>. So I can serialize IRecordable arrays by replacing them with string arrays, and deserialize them by deserializing the object at location recorded in each string.

Oh, and about creating the destination array, can't I just do destination = source.Clone()? I mean if I clone it, it will have the same dimensions, right? The types would be wrong, but Array isn't generic, so it should be fine.

Also, I already have recording IRecordable[,,,,,,] working. So as long as I can apply it to IRecordable[][][] I should be fine. I think I got a better idea of how to do it now. Thanks.

Share this post


Link to post
Share on other sites
If this is solely for serialization / deserialization, you might look into the built-in .Net serialization routines. They're SCARY how much stuff they'll do automatically. They can supposedly figure out how to serialize and deserialize graph data structures that have looping references, etc. I think your array would be easier than that for it to handle.

Share this post


Link to post
Share on other sites

This topic is 4349 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this