Когда я пишу целую таблицу в рабочий лист Excel, я знаю для работы с целым Диапазоном сразу вместо того, чтобы писать в отдельные ячейки. Однако есть ли способ указать формат, поскольку я заполняю массив, который я собираюсь экспортировать в Excel?
Вот то, что я делаю теперь:
object MissingValue = System.Reflection.Missing.Value;
Excel.Application excel = new Excel.Application();
int rows = 5;
int cols = 5;
int someVal;
Excel.Worksheet sheet = (Excel.Worksheet)excel.Workbooks.Add(MissingValue).Sheets[1];
Excel.Range range = sheet.Range("A1", sheet.Cells(rows,cols));
object[,] rangeData = new object[rows,cols];
for(int r = 0; r < rows; r++)
{
for(int c = 0; c < cols; c++)
{
someVal = r + c;
rangeData[r,c] = someVal.ToString();
}
}
range.set_Value(MissingValue, rangeData);
Теперь предположите, что я хочу, чтобы некоторые из тех чисел были отформатированы как проценты. Я знаю, что могу возвратиться на основе ячейки ячейкой и изменить форматирование, но это, кажется, побеждает целую цель использовать единственный Диапазон set_Value () вызов. Я могу сделать свой rangeData [] структура включают информацию о форматировании, так, чтобы, когда я называю set_Value (), ячейки были отформатированы в способе, которым я хочу их?
Для разъяснения я знаю, что могу установить формат для всего Excel. Объект диапазона. Тому, что я хочу, нужно было указать другой формат для каждой ячейки, указанной во внутреннем цикле.
Итак, вот лучшее «решение», которое я нашел до сих пор. Это не та нирванна, которую я искал, но она намного быстрее, чем установка формата для каждой ячейки в отдельности.
// 0-based indexes
static string RcToA1(int row, int col)
{
string toRet = "";
int mag = 0;
while(col >= Math.Pow(26, mag+1)){mag++;}
while (mag>0)
{
toRet += System.Convert.ToChar(64 + (byte)Math.Truncate((double)(col/(Math.Pow(26,mag)))));
col -= (int)Math.Truncate((double)Math.Pow(26, mag--));
}
toRet += System.Convert.ToChar(65 + col);
return toRet + (row + 1).ToString();
}
static Random rand = new Random(DateTime.Now.Millisecond);
static string RandomExcelFormat()
{
switch ((int)Math.Round(rand.NextDouble(),0))
{
case 0: return "0.00%";
default: return "0.00";
}
}
struct ExcelFormatSpecifier
{
public object NumberFormat;
public string RangeAddress;
}
static void DoWork()
{
List<ExcelFormatSpecifier> NumberFormatList = new List<ExcelFormatSpecifier>(0);
object[,] rangeData = new object[rows,cols];
for(int r = 0; r < rows; r++)
{
for(int c = 0; c < cols; c++)
{
someVal = r + c;
rangeData[r,c] = someVal.ToString();
NumberFormatList.Add(new ExcelFormatSpecifier
{
NumberFormat = RandomExcelFormat(),
RangeAddress = RcToA1(rowIndex, colIndex)
});
}
}
range.set_Value(MissingValue, rangeData);
int max_format = 50;
foreach (string formatSpecifier in NumberFormatList.Select(p => p.NumberFormat).Distinct())
{
List<string> addresses = NumberFormatList.Where(p => p.NumberFormat == formatSpecifier).Select(p => p.RangeAddress).ToList();
while (addresses.Count > 0)
{
string addressSpecifier = string.Join(",", addresses.Take(max_format).ToArray());
range.get_Range(addressSpecifier, MissingValue).NumberFormat = formatSpecifier;
addresses = addresses.Skip(max_format).ToList();
}
}
}
В основном происходит то, что я храню список информации о формате для каждой ячейки в NumberFormatList (каждый элемент также содержит адрес в стиле A1 диапазона, к которому он применяется). Первоначальная идея заключалась в том, что для каждого отдельного формата на листе я должен иметь возможность создать Excel.Range только из этих ячеек и применить формат к этому диапазону за один вызов. Это уменьшит количество обращений к NumberFormat с (потенциально) тысяч до нескольких (сколько бы разных форматов у вас ни было).
Я столкнулся с проблемой, потому что вы, очевидно, не можете построить диапазон из произвольно длинного списка ячеек. После некоторого тестирования я обнаружил, что предел составляет от 50 до 100 ячеек, которые можно использовать для определения произвольного диапазона (например, range.get_Range ("A1, B1, C1, A2, AA5, .....") . Итак, как только я получил список всех ячеек, к которым нужно применить формат, у меня есть последний цикл while (), который применяет формат к 50 из этих ячеек за раз.
Это не идеально, но это по-прежнему сокращает количество обращений к NumberFormat в 50 раз, что является значительным. Создание моей электронной таблицы без какой-либо информации о формате (только с использованием range.set_Value ()) занимает около 3 секунд. Когда я применяю форматы, 50 ячеек в время, которое удлиняется примерно до 10. Когда я применяю информацию о формате индивидуально к каждой ячейке, создание таблицы занимает более 2 минут!
Вы можете применить форматирование к диапазону, а затем заполнить его значениями, которые вы не можете указать форматирование в вашем массиве object [,]
Вы не можете сделать это, потому что нет кодировки команд MIPS, которая поддерживает такую вещь. Вы должны сделать сложение самостоятельно:
add $a2, $a1, $t2
lw $s2, 0($a2)
Кодировка команды lw
выглядит следующим образом:
1000 11ss ssst tttt iiii iiii iiii iiii
Где sssss
- номер исходного регистра, ttttt
- номер целевого регистра, а iiiiiiiiiiii
- немедленный. В этом кодировании нет места (и нет альтернативных кодировок команд), которые используют два регистра для генерации адреса памяти. Конкретная машинная команда, которая будет закодирована из приведенного выше примера:
1000 1100 1101 0010 0000 0000 0000 0000
Поскольку непосредственный - 0
, $ s2
является регистром 18
и $ a2
является регистром 6
.
Я бы сказал, что это полностью зависит от заданных временных рамок. Если у вас есть время потратить почти в два раза больше времени, чем вы бы обычно требовали, тогда идите на это. Но на мой взгляд скорость - это в наши дни один из важнейших факторов (для конкурентоспособных компаний).
-121--1150847-Форматирование применяется к каждой отдельной ячейке во внутреннем цикле с помощью
for(int r = 0; r < rows; r++)
{
for(int c = 0; c < cols; c++)
{
Excel.Range r2 = sheet.Cells( r, c );
r2.xxxx = "";
}
}
После r2
можно изменить формат ячейки любым способом.