Как я могу преобразовать двумерный массив в штучной упаковке в массив двумерных строк за один шаг?

Есть ли способ преобразовать двухмерный массив в штучной упаковке в массив двумерных строк за один шаг с помощью C#/.NET Framework 4.0?

using ( MSExcel.Application app = MSExcel.Application.CreateApplication() ) {
    MSExcel.Workbook book1 = app.Workbooks.Open( this.txtOpen_FilePath.Text );
    MSExcel.Worksheet sheet1 = (MSExcel.Worksheet)book1.Worksheets[1];
    MSExcel.Range range = sheet1.GetRange( "A1", "F13" );
    object value = range.Value; //the value is boxed two-dimensional array
}

Я надеюсь, что какая-то форма Array.ConvertAll может работать, но до сих пор ответ ускользал от меня.


person WeekendDiver    schedule 19.05.2011    source источник
comment
Каков фактический тип value? Это просто Object[][]?   -  person Daniel Schaffer    schedule 20.05.2011
comment
Согласно документации, это System.object: msdn.microsoft.com/en-us/library/   -  person WeekendDiver    schedule 20.05.2011
comment
Извините, я имел в виду тип среды выполнения, а не тип свойства. Если вы вызовете GetType() для этого значения, что это будет?   -  person Daniel Schaffer    schedule 20.05.2011
comment
Каков результат value.GetType()?   -  person svick    schedule 20.05.2011
comment
GetType() возвращает System.Object[,] для значения.   -  person WeekendDiver    schedule 20.05.2011


Ответы (3)


Нет, я не думаю, что вы можете сделать преобразование за один шаг, но я могу ошибаться. Но вы, конечно, можете создать новый массив и скопировать из старого в новый:

object value = range.Value; //the value is boxed two-dimensional array
var excelArray = value as object[,];
var height = excelArray.GetLength(0);
var width = excelArray.GetLength(1);
var array = new string[width, height];
for (int i = 0; i < height; i++)
{
    for (int j = 0; j < width; j++)
        array[i, j] = excelArray[i, j] as string;
}

Изменить:

Вот двумерная перегрузка Array.ConvertAll, которая ненамного сложнее приведенного выше кода:

public static TOutput[,] ConvertAll<TInput, TOutput>(TInput[,] array, Converter<TInput, TOutput> converter)
{
    if (array == null)
    {
        throw new ArgumentNullException("array");
    }
    if (converter == null)
    {
        throw new ArgumentNullException("converter");
    }
    int height = array.GetLength(0);
    int width = array.GetLength(1);
    TOutput[,] localArray = new TOutput[width, height];
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
            localArray[i, j] = converter(array[i, j]);
    }
    return localArray;
}
person Rick Sladkey    schedule 19.05.2011
comment
Это был подход, к которому я собирался прибегнуть, если бы не смог сделать это за один шаг. Цель состоит в том, чтобы использовать встроенную функцию .NET, если я смогу ее найти. Согласно документации, Array.ConvertAll должен это сделать, но мне пока не удалось заставить его работать. - person WeekendDiver; 20.05.2011
comment
Добавляю идею, думаю, вам понравится. - person Rick Sladkey; 20.05.2011
comment
@Driver, согласно документу, ConvertAll() принимает “ одномерный, Array с отсчетом от нуля». - person svick; 20.05.2011
comment
Это решение сработало для меня, но мне пришлось внести пару изменений. 1) excelArray начинается с [1,1], а новый массив начинается с [0,0]. Таким образом, мне пришлось изменить одну строку в цикле for, чтобы учесть это смещение: array[i, j] = excelArray[i+1, j+1].ToString(); 2) нужно поменять местами высоту/ширину в строке, создающей массив: var array = new string[height, width]; В остальном это сработало именно так, как мне было нужно - спасибо! - person WeekendDiver; 20.05.2011
comment
Рад, что смог помочь. Эти типы массивов встречаются редко, но они поддерживаются фреймворком. В общем случае вам потребуется использовать GetLowerBound: msdn. microsoft.com/en-us/library/ - person Rick Sladkey; 20.05.2011

Вы можете написать свой собственный ConvertAll для двумерных массивов:

public static TOutput[,] ConvertAll<TInput, TOutput>(
    this TInput[,] array, Func<TInput, TOutput> converter)
{
    int length0 = array.GetLength(0);
    int length1 = array.GetLength(1);

    var result = new TOutput[length0, length1];

    for (int i = 0; i < length0; i++)
        for (int j = 0; j < length1; j++)
            result[i, j] = converter(array[i, j]);

    return result;
}
person svick    schedule 19.05.2011
comment
Это очень близко к тому, что я ищу, но я надеялся, что .NET Framework уже включает что-то подобное. Array.ConvertAll начинает жаловаться, если я указываю более одного измерения, что было удивительно. - person WeekendDiver; 20.05.2011

string[][] strings = ((object[][])range.Value)
    .Select(x => x.Select(y => y.ToString()).ToArray()).ToArray();

Правка: уточнение об объекте[,] вместо объекта[][] явно делает этот подход устаревшим. Интересная проблема; многомерные массивы весьма ограничены.

person Calvin Fisher    schedule 19.05.2011
comment
С какой стати вы использовали бы здесь AsQueryable? - person Joel Mueller; 20.05.2011
comment
Ха. Я думаю, что у меня появилась эта привычка, когда я впервые изучал LINQ. Это это довольно глупо, раз уж вы об этом упомянули. Отредактировано. - person Calvin Fisher; 20.05.2011