Главная » C# » Работа с электронной таблицей в Visual C# (Sharp)

0

Теперь, когда интерфейсы и их реализации готовы, мы можем использовать элеронную таблицу. Для примера возьмем таблицу для вычисления среднего по нору чисел, после чего вычислим отклонение каждого числа от среднего значения.

Вычисление среднего значения

Таблица вычисляет среднее значение набора чисел, которое потом отнимается от каждого числа набора. Пример демонстрирует считывание всей таблицы, чтобы получить среднее значение, и считывание отдельных элементов для выполнения вычислений. Вычислим среднее значение следующих чисел:

double[] items = new doublet] { 1.0, 2.0, 3.0 };

Среднее значение будет 2. о, а вычисление отклонения каждого числа от среднего дает последовательность -1 , 0 и 1.

Чтобы выполнить эти вычисления в электронной таблице, первым шагом нужно объявить и заполнить экземпляр iworksheeto. Для создания экземпляра iworksheeto мы применим фабрику, которая создаст  нам  экземпляр  класса worksheeto. Код для этого выглядит таким образом:

IWorksheet<double> sheetAverage = SpreadsheetManager.CreateEmpytWorksheet<double>("");

doublet] items = new doublet] { 1.0, 2.0, 3.0 }; sheetAverage.Dimension(items.Length + 10, 3); for (int row = 0; row < items.Length; row++) {

sheetAverage.SetCellState(row, 0, items[row]);

}

Тип листа таблицы объявляется как double (iworksheet<double>), что позволит нам работать с числами двойной точности. Чтобы заполнить sheetAverage, числа обрабатываются в цикле for, после чего присваиваются таблице с помощью метода SetCellState (). Метод Dimension о необходим для создания таблицы фиксиранных размеров.

Чтобы  проверить, успешно ли  прошло заполнение таблицы, можно вызвать метод

Tostring ()  и посмотреть, все ли выглядит должным образом.

Следующим шагом будет присвоение значений лямбда-выражениям, с помощью которых будет вычислено среднее значение и отклонения от среднего. Присваая операцию вычисления таблице, требуется знать, будет ли лямбда-выражение иметь состояние или нет. Вспомните, что лямбда-выражения имеют состояния, поэтому это всего лишь вопрос, хотим ли мы получить лямбда-выражение с раеляемым состоянием или же лямбда-выражение с индивидуальным состоянием. Для лямбда-выражений для вычисления среднего значения приемлемым будет разделяемое состояние.

Вычисление  среднего  значения  выполняется  последним   в   последовательнти вычислений с массивом. Поэтому при вызове этого вычисления уже имеется информация о количестве  элементов в виде строки таблицы, в которой оно сранено.

sheetAverage.AssignCellCalculation(items.Length,  0, (IWorksheet<double> worksheet, int cellRow, int cellCol) => {

double runningTotal = 0.0;

for (int row = 0; row < cellRow; row++) { runningTotal += worksheet.GetCellState(row, 0);

}

return runningTotal / cellRow;

}) ;

В примере среднее значение вычисляется с помощью переменной cellRow, в котой хранится значение максимального числа рядов таблицы. Значение каждой ячейки (GetCellStateо), меньшее, чем cellRow, добавляется к текущей сумме (runningTotal), после чего вычисляется и возвращается среднее значение, поленное делением runningTotal на cellRow..

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

for (int row = 0; row < items.Length; row++) { sheetAverage.AssignCellCalculation(row,  1,

(worksheet, cellRow, cellCol) => (

return worksheet.GetCellState(cellRow, 0) – worksheet.Calculate(items.Length,  0);

) ;

}

Количество  вычислений  состояния  ячейки  зависит от значения  числа элементов в items. Каждому вычислению ячейки присваивается локально объявленное лямбда-выражение, означающее, что лямбда-выражения всех состояний ячеек будут одинаковыми и разделять одно состояние. Единственной разделяемой пеменной является переменная items.Length. Все лямбда-выражения ожидают одну и ту же длину, поэтому разделение данной переменной является  допустым. Отклонение вычисляется вычитанием среднего значения от значения ячеи в нулевом столбце.

Наконец,     когда     все     присваивания     выполнены,     можно     вызывать     метод worksheet.Calculate() для вычисления среднего и отклонения от среднего: sheetAverage.Calculate();

Console. WriteLine(sheetAverage.ToString());

Объяснение работы вычислений

Вычисления в ячейках работают, потому что таблица обладает возможностью олеживать, какие вычисления были выполнены, а какие нет. В обычной электроой таблице при изменении значения одной из ячеек автоматически выполняется пересчет всех  остальных ячеек листа. В данной электронной таблице такой воожности нет. Но в ней имеется упрощенная версия такой возможности, которая обеспечивает, что в случае наличия зависимостей между ячейками, ячейки не перчитываются по несколько раз.

Посмотрите опять на исходный код для вычисления отклонения значения ячейки от среднего значения. Единственно, почему эти  вычисления  выполняются  успешно, так это потому, что ячейка, содержащая среднее значение, вызывается с помощью метода calculate о.  Если бы был использован метод Getceiistatef), то среднее значение могло оказаться невычисленным, и результаты вычисления отклонения могли бы быть искаженными.

Но вычисление среднего значения каждой ячейкой при любом, каким бы незначельным оно ни было, изменении является напрасной тратой ресурсов, т. к. измения могут не затрагивать пересчитываемую ячейку. Чтобы предотвратить это, в таблицу встроен механизм контроля версий, который вычисляет ячейку только до последней версии. Потом,  если вызывается  вычисление с таким же номером веии, то значение не вычисляется, а извлекается из состояния ячейки. Далее привится код из worksheet<> для управления номерами версий:

public BaseType Calculate(int row, int col) {

if (CurrVersion > CalculationVersionfrow, col]) { CellState[row, col] = Cells[row, col](this, row, col); CalculationVersion[row, col] = CurrVersion;

}

return CellState[row, col];

}

public void Calculate() { CurrVers ion++;

for (int row = 0; row < Cells.GetLength(0); row++) {

for (int col = 0; col < Cells.GetLength(1); col++)  {

if (Cells[row, col] != null) { Calculate(row, col);

}

}

}

}

Вызов метода Calculate о без параметров указывает на необходимость пересчать всю таблицу. В реализации метода Calculate о выполняется увеличение пеменной CurrVersion, которая представляет номер версии текущего вычисления.

Потом выполняется проход в цикле по всем ячейкам и вызывается индивидуальная версия метода Calculate о для ячейки (метод, содержащий параметры row и col), если таковая имеется. В этой версии Calculate о проверяет, не является ли номер версии вычисления самым последним в таблице, и если нет, то вызывается лямбдыражение ячейки. После присваивания нового CellState, номер версии состояния ячейки увеличивается на один и возвращается состояние ячейки.

ПРИМЕЧАНИЕ

Вычисления в электронной таблице не представляют собой ничего из ряда вон выхящего, и можно утверждать,  что  они  не  имеют  никакого  отношения  к  предмету  даой книги. Но в действительности такие вычисления и их сторонние эффект ы имею т большую важность. Лямбда-выражени я являются видом асинхронной обработки, нодобие электронной  таблицы.  Вычисления  ячеек  электронной  таблиц ы  не  знают,  кда они будут вызваны, и они не могут  делать предположений о состоянии. Поэтому состояние  при  создании  лямбда-выражения  может отличаться  от состояния  при  вызе  этого  выражения.  Если  вы  четко  не  осознаете  этой  возможной  проблемы,  то  може  допустить  серьезные  ошибки  в  разрабатываемом  коде.

Источник: Гросс  К. С# 2008:  Пер. с англ. — СПб.:  БХВ-Петербург, 2009. — 576 е.:  ил. — (Самоучитель)

По теме:

  • Комментарии