12

How would you convert object[,] to string[,] ?

Object[,] myObjects= // sth
string[,] myString = // ?!? Array.ConvertAll(myObjects, s => (string)s) // this doesn't work

Any suggestions appreciated.

EDIT : Of course, a loop solution will obviously do it, however I was envisioning a more elegant solution both in terms of code and in performance.

EDIT2 : The object[,] contains of course strings (and digits, but this doesn't matter for now).

HeinrichStack
  • 694
  • 3
  • 8
  • 28
  • 2
    Are you actually trying to convert to `string[,]` or `string[]`? Your question is inconsistent. – Jon Skeet Apr 30 '13 at 10:40
  • I assume two nested loops are out of the question? – Kobi Apr 30 '13 at 10:40
  • Why can't you just use some loops – Hogan Apr 30 '13 at 10:41
  • When you say convert, do you mean call `ToString()` or should the code fail if the `object`s are not `string`s? – Jodrell Apr 30 '13 at 10:43
  • can anyone please tell me what [,] is, i mean, i haven't seen it before, but the compiler accepts it. any reference is welcome. – Victor Mukherjee Apr 30 '13 at 10:43
  • @VictorMukherjee a multidimensional array. – Jodrell Apr 30 '13 at 10:45
  • @VictorMukherjee http://msdn.microsoft.com/en-us/library/2yd9wwz4.aspx – Soner Gönül Apr 30 '13 at 10:53
  • It looks like you assume all the entries are already strings, since you simply say `(string)s` in the commented-out part. If it is possible that `myObjects` really has the runtime-type of a `string[,]`, start by checking that: `var myStrings = myObjects as string[,]; if (myStrings == null) { /* do as suggested in the answers instead */ }` – Jeppe Stig Nielsen Apr 30 '13 at 10:55
  • 1
    some details on why multidimensional arrays suck http://stackoverflow.com/q/275073/659190, I'd be tempted to convert to `IList>`. – Jodrell Apr 30 '13 at 10:56
  • 2
    Multi-dimensional arrays are not collections, nothing can be done except for looping (or converting throuhg black magic). If the `Object[,]` actually contains strings, why isn't it a `string[,]` in the first place ? – Alex Apr 30 '13 at 11:04
  • 1
    Note that every kind of LINQ queries / extension methods (and similar) are just a **beautiful** way to DO RAW **FOR** LOOPS. You'll probably get NO performance improvement at all. – Teejay Apr 30 '13 at 11:06
  • @Jodrell : They are all strings, or at least convertible to strings. – HeinrichStack Apr 30 '13 at 11:09
  • @Alex : 10x. So, looping is the only solution ? It contains `object[,]` and not `string[,]`, because it comes from a generic table, which may contains stuff other than `string`s, but in my case I know for sure they are only `string`s, and I want to post process them. – HeinrichStack Apr 30 '13 at 11:11

4 Answers4

4
Object[,] myObjects = new Object[3, 2] { { 1, 2 }, { 3, 4 },
                                        { 5, 6 } };

string[,] myString = new string[3, 2];

for (int i = myObjects.GetLowerBound(0); i < myObjects.GetUpperBound(0); i++)
{
     for (int j = myObjects.GetLowerBound(1); j < myObjects.GetUpperBound(1); j++)
     {
          myString[i, j] = myObjects[i, j].ToString();
     }
}

foreach (var item in myString)
{
    Console.WriteLine("{0} - {1}", item.GetType(), item);
}

Output will be;

System.String - 1
System.String - 2
System.String - 3
System.String - 4
System.String - 5
System.String - 6
Soner Gönül
  • 97,193
  • 102
  • 206
  • 364
  • 1
    [What if the array's lower bounds are not 0](http://msdn.microsoft.com/en-us/library/x836773a.aspx)? – ta.speot.is Apr 30 '13 at 11:05
  • @Soner Gönül : 10x, however I was envisioning a more elegant solution in terms of code and performance. This will obviously do. as well. – HeinrichStack Apr 30 '13 at 11:05
  • @HeinrichStack I research this type of conversion for multidiamentionals array but I coulnd't find any better way to do this. – Soner Gönül Apr 30 '13 at 11:11
  • @ta.speot.is from the [Array.CreateInstance](http://msdn.microsoft.com/en-us/library/x836773a.aspx) article: >Generally, the .NET Framework class library and many programming languages do not handle nonzero lower bounds. – Johnbot Apr 30 '13 at 17:17
  • @Johnbot I merely asked the question, "what if the array's lower bounds are not 0". – ta.speot.is Apr 30 '13 at 21:21
4

You can allocate space like this

string[,] myString = new string[myObjects.GetLength(0),myObjects.GetLength(1)];

Then some loops should work fine, like this:

for(int k=0;k < myObjects.GetLength(0);k++)
    for(int l=0;l < myObjects.GetLength(1);l++)
        myString[k,l] = myObjects[k,l].ToString();
Hogan
  • 69,564
  • 10
  • 76
  • 117
  • 1
    @HeinrichStack, This is good, assuming `ToString` provides the conversion you require. For many classes that do not override `ToString()` the type name in braces is less than useful. However, you can't expect "useful" to be automatically defined for you, its context sensitive. – Jodrell Apr 30 '13 at 10:48
  • you don't instantiate `myString` – Jodrell Apr 30 '13 at 10:49
  • @Jodrell - I didn't assign values to myObjects too, I'm assuming there is other code, this is just a snippet, but you have a point. – Hogan Apr 30 '13 at 10:50
  • @Hogan 10x, however I was envisioning a more elegant solution in terms of code and performance. This will obviously do. as well. – HeinrichStack Apr 30 '13 at 11:02
  • 1
    [What if the array's lower bounds are not 0](http://msdn.microsoft.com/en-us/library/x836773a.aspx)? – ta.speot.is Apr 30 '13 at 11:07
  • @ta.speot.is - Then it would be slightly more complicated -- the allocation and the loop would need to account for it. – Hogan Apr 30 '13 at 11:31
4

Given the other answers, it's really easy to write your own ConvertAll method for 2D arrays:

public static TOutput[,] ConvertAll<TInput, TOutput>(TInput[,] array, Func<TInput, TOutput> converter)
{
    var result = new TOutput[array.GetLength(0), array.GetLength(1)];
    for (int i = 0; i < array.GetLength(0); ++i)
        for (int j = 0; j < array.GetLength(1); ++j)
            result[i, j] = converter(array[i, j]);

    return result;
}

Just because the authors of .NET didn't care to include this method, there's no need to give up entirely. It's pretty straight forward to write it yourself.

(You could make it an extension method if you wanted.)

EDIT after comments: If you really want to handle arrays whose lower bound (in some dimension) is not zero, it goes like this:

public static TOutput[,] ConvertAll<TInput, TOutput>(TInput[,] array, Func<TInput, TOutput> converter)
{
    int xMin = array.GetLowerBound(0);
    int xLen = array.GetLength(0);
    int yMin = array.GetLowerBound(1);
    int yLen = array.GetLength(1);
    var result = (TOutput[,])Array.CreateInstance(typeof(TOutput), new[] { xLen, yLen, }, new[] { xMin, yMin, });
    for (int x = xMin; x < xMin + xLen; ++x)
        for (int y = yMin; y < yMin + yLen; ++y)
            result[x, y] = converter(array[x, y]);

    return result;
}
Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181
  • 1
    @ta.speot.is I implicitly assumed that the 2D array was created with usual C# syntax. Of course I know it is possible to create an array like this: `(object[,])Array.CreateInstance(typeof(object), new[] { 10, 20, }, new[] { -3, -7, });`, but who does that? This question was tagged C#, you know. Should I include code to handle this unlikely case? – Jeppe Stig Nielsen Apr 30 '13 at 11:26
  • *This question was tagged C#, you know* What language is `(object[,])Array.CreateInstance(typeof(object), new[] { 10, 20, }, new[] { -3, -7, });` written in? – ta.speot.is Apr 30 '13 at 11:27
  • @ta.speot.is provide a better solution – WiiMaxx Apr 30 '13 at 11:31
  • @WiiMaxx [I'd just be re-posting this answer](http://stackoverflow.com/a/16297879/242520). – ta.speot.is Apr 30 '13 at 11:32
  • 2
    @ta.speot.is Alright, I included the case with non-zero lower bounds. Not that I think ___any___ C# developer uses it. – Jeppe Stig Nielsen Apr 30 '13 at 11:34
  • @ta.speot.is so that's the best way to do it? i was hopping there would maybe an generic way to do this like this one – WiiMaxx Apr 30 '13 at 11:35
  • @WiiMaxx Just take the answer I linked to and generalise it. – ta.speot.is Apr 30 '13 at 11:36
  • @JeppeStigNielsen Thank you. Bonus points for preserving the lower bound for the new array. – ta.speot.is Apr 30 '13 at 11:36
  • @ta.speot.is You really need only the first version, before my edit. I promise. – Jeppe Stig Nielsen Apr 30 '13 at 11:39
3

This should be one of the simplest and the fastest way, assuming that every element in the src array can be cast down to the dst array type.

object[,] src = new object[,]
{
    {"foo", "bar"},
    {"spam", "eggs"},
};

string[,] dest = new string[src.GetLength(0), src.GetLength(1)];
Array.Copy(src, dest, src.Length);
Paolo Moretti
  • 54,162
  • 23
  • 101
  • 92
  • [This doesn't preserve the lower bound of the source array](http://msdn.microsoft.com/en-au/library/system.array.getlowerbound.aspx). – ta.speot.is Apr 30 '13 at 11:25
  • @ta.speot.is : Thas true, so possible trick will be to fill the rest with null, and copy to that area. Or do you have a better idea? – HeinrichStack Apr 30 '13 at 11:42
  • @Paolo Moretti : nice solution. – HeinrichStack Apr 30 '13 at 11:44
  • @WiiMaxx : what did you use, `double`s ? – HeinrichStack Apr 30 '13 at 11:44
  • @HeinrichStack i just changed `"eggs"` to `5` – WiiMaxx Apr 30 '13 at 11:46
  • @WiiMaxx In my opinion it doesn't make any sense create an object array containing multiple types (e.g `{"spam", 5, 1.0}`) and then pretending that some magic method can perform all the conversions we are expecting; :) especially if you consider that there are several of ways to convert a number to string, depending on the `CultureInfo` for example. – Paolo Moretti Apr 30 '13 at 11:54
  • @PaoloMoretti i mentioned the digits only because of the 2Edit from the OP _"(and digits, but this doesn't matter for now)."_ .So no worries i'm fine with your solution – WiiMaxx Apr 30 '13 at 11:59
  • @WiiMaxx : Indeed, the `Array.Copy` method crashes with digits. I will need time to understand, why this is happening and how to be avoided. I thought digits will be treated easily some how, once it is done with strings. Moreover, I tried object[] with only digits. The same problem with the Copy method. – HeinrichStack Apr 30 '13 at 11:59
  • @Paolo Moretti : the sense with the array with multiple types come e.g. when working with Excel Tables, than you would have these multiple types in it. – HeinrichStack Apr 30 '13 at 12:03
  • @HeinrichStack It crashes because `Array.Copy` is performing a cast for every element and casting a number to string raise an `InvalidCastException`. Try this code, for example: `object n = 1; string s = (string)n;` – Paolo Moretti Apr 30 '13 at 12:03
  • @HeinrichStack maybe you should test Jeppe Stig Nielsen [EDIT version](http://stackoverflow.com/a/16298512/1993545) i don't know how but it works :D – WiiMaxx Apr 30 '13 at 12:04
  • @WiiMaxx : I was having a similar solution before posting the question. – HeinrichStack Apr 30 '13 at 12:06
  • @Paolo Moretti : I didn't quite get your answer? What will be the exact calling of the Array.CopyMethod ? – HeinrichStack Apr 30 '13 at 12:07