简体   繁体   中英

Converting Object [,] to String[,]

I am trying to convert an object[,] array (with for example some integers in it) to a string[,] array. I wrote this piece of code but Visual Studio gives me an error saying:

Cannot implicitly convert String[] to String[,] .

What argument should I give to the Array.ConvertAll function? Thanks a lot.

object[,] input = GetSelectedRange();

string[,] dst = Array.ConvertAll<object[,], string[,]>(
    input, 
    x => x.ToString()
);

It would have been a lot easier if your item is object[][] rather than object[,] . But for object[,] , why not using traditional method?

object[,] input = GetSelectedRange();
string[,] output = new string[input.GetLength(0), input.GetLength(1)];
for (int i = 0; i < input.GetLength(0); ++i)
    for (int j = 0; j < input.GetLength(1); ++j)
        output[i, j] = input[i, j]?.ToString(); //give additional ?. to check if your input is null

Suggestion by Olivier : to check if your input is null by using C#6 syntax ?.

Or, if you use lower version, use ternary operator:

object[,] input = GetSelectedRange();
string[,] output = new string[input.GetLength(0), input.GetLength(1)];
for (int i = 0; i < input.GetLength(0); ++i)
    for (int j = 0; j < input.GetLength(1); ++j)
        output[i, j] = input[i, j] == null ? null input[i, j].ToString();

Array.ConvertAll() only handles one-dimensional arrays. The input is expected to be an array of the input type and produces an array of the output type. The converter is expecting something that can convert object[,] -> string[,] .

Multi-dimensional arrays do not have generic convert method, you would have to do it by hand. You could do something like this:

public TOutput[,] ConvertAll<TInput, TOutput>(TInput[,] input, Func<TInput, TOutput> converter)
{
    var length0 = input.GetLength(0);
    var length1 = input.GetLength(1);
    var result = new TOutput[length0, length1];
    for (var i = 0; i < length0; ++i)
    for (var j = 0; j < length1; ++j)
        result[i, j] = converter(input[i, j]);
    return result;
}

Then you could do this to do the conversion:

var input = GetSelectedRange();
var converted = ConvertAll(input, x => x.ToString());

If it's possible that the source array is not 0-based, some adjustments would need to be made to handle the changed bounds.

public TOutput[,] ConvertAll<TInput, TOutput>(TInput[,] input, Func<TInput, TOutput> converter)
{
    var lengths = new[] { input.GetLength(0), input.GetLength(1) };
    var lowers = new[] { input.GetLowerBound(0), input.GetLowerBound(1) };
    var uppers = new[] { input.GetUpperBound(0), input.GetUpperBound(1) };
    var result = Array.CreateInstance(typeof(TOutput), lengths, lowers) as TOutput[,];
    for (int i = lowers[0], il = uppers[0]; i <= il; ++i)
    for (int j = lowers[1], jl = uppers[1]; j <= jl; ++j)
            result[i, j] = converter(input[i, j]);
    return result;
}

For a general purpose converter that can handle all arrays, this could be used.

public Array ConvertAll<TInput, TOutput>(Array input, Func<TInput, TOutput> converter)
{
    var rank = input.Rank;
    var lengths = Enumerable.Range(0, rank).Select(i => input.GetLength(i)).ToArray();
    var lowerBounds = Enumerable.Range(0, rank).Select(i => input.GetLowerBound(i)).ToArray();
    var upperBounds = Enumerable.Range(0, rank).Select(i => input.GetUpperBound(i));
    var output = Array.CreateInstance(typeof(TOutput), lengths, lowerBounds);
    ConvertRank(input, converter, output, new int[0], lowerBounds.Zip(upperBounds, Tuple.Create).ToArray());
    return output;
}

private void ConvertRank<TInput, TOutput>(Array input, Func<TInput, TOutput> converter, Array output, int[] indices, Tuple<int, int>[] bounds)
{
    if (!bounds.Any())
    {
        var value = input.GetValue(indices);
        var convertedValue = converter((TInput)value);
        output.SetValue(convertedValue, indices);
    }
    else
    {
        var start = bounds[0].Item1;
        var end = bounds[0].Item2;
        var tail = bounds.Skip(1).ToArray();
        for (var i = start; i <= end; i++)
            ConvertRank(input, converter, output, indices.Concat(new[] { i }).ToArray(), tail);
    }
}

You'll just need to cast back the array to the expected type (since the rank could not be expressed).

object[,,] input = GetSome3dObjectArray();
var converted = ConvertAll(input, (object x) => x.ToString()) as string[,,];

If you wanted some strong typing, you could create the appropriate overloads for the types you want to support.

public TOutput[,] ConvertAll<TInput, TOutput>(TInput[,] input, Func<TInput, TOutput> converter) =>
    ConvertAll((Array)input, converter) as TOutput[,];
public TOutput[,,] ConvertAll<TInput, TOutput>(TInput[,,] input, Func<TInput, TOutput> converter) =>
    ConvertAll((Array)input, converter) as TOutput[,,];

From: https://stackoverflow.com/a/5083690/380384

object[,] src = new object[2, 3];

// Initialize src with test strings.
src[0, 0] = "aa";
src[0, 1] = "ab";
src[0, 2] = "ac";
src[1, 0] = "ba";
src[1, 1] = "bb";
src[1, 2] = "bc";

string[,] dst = new string[src.GetLength(0), src.GetLength(1)];
Array.Copy(src, dst, src.Length);

Note that this not converting but re-casting. It works if the object elements are really string elements (like what comes from a Excel worksheet).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM