Я импортирую файл excel в таблицу данных (dtImport) и перестраиваю эти данные в другую таблицу данных (dtImportParsed).
Вот как выглядит эта таблица данных (dtImport), когда я впервые импортирую ее.
И вот как я пытаюсь изменить эту таблицу данных (dtImportParsed):
В настоящее время я выполняю это, используя несколько вложенных циклов for, но это занимает очень много времени. Например, лист с 36 столбцами и 4000 строк заполняется примерно за 30–40 минут. Есть ли альтернативный способ сделать это, который ускорит процесс?
Вот мой код:
for (int c = 2; c < dtImport.Columns.Count; c++) //for each date column
{
for (int r = 1; r < dtImport.Rows.Count; r++)
{
if (dtImportParsed.Rows.Count == 0)
{
DataRow dataRowImport = dtImportParsed.NewRow();
dataRowImport["Date"] = dtImport.Columns[c].ColumnName.ToString().Trim();
dataRowImport["account_id"] = dtImport.Rows[r]["account_id"].ToString().Trim();
dataRowImport[dtImport.Rows[r]["Event Name"].ToString().Trim()] = dtImport.Rows[r][c].ToString().Trim();
dtImportParsed.Rows.Add(dataRowImport);
}
else
{
for (int i = 0; i < dtImportParsed.Rows.Count; i++)
{
if (dtImportParsed.Rows[i]["account_id"].ToString() == dtImport.Rows[r]["account_id"].ToString())
{
if (dtImportParsed.Rows[i]["Date"].ToString() == dtImport.Columns[c].ColumnName.ToString())
{
dtImportParsed.Rows[i][dtImport.Rows[r]["Event Name"].ToString().Trim()] = dtImport.Rows[r][c].ToString().Trim();
break;
}
}
else if (i == dtImportParsed.Rows.Count - 1)
{
DataRow dataRowImport = dtImportParsed.NewRow();
dataRowImport["Date"] = dtImport.Columns[c].ColumnName.ToString().Trim();
dataRowImport["account_id"] = dtImport.Rows[r]["account_id"].ToString().Trim();
dataRowImport[dtImport.Rows[r]["Event Name"].ToString().Trim()] = dtImport.Rows[r][c].ToString().Trim();
dtImportParsed.Rows.Add(dataRowImport);
}
}
}
}
}
Привет, сводка в excel не поворачивает таблицу так, как мне нужно, к сожалению :(. Также нет доступа к базе данных
Алгоритм, который вы используете для получения ожидаемого результата, слишком дорог! Он будет выполняться в порядке (c x r x i)
, где i > r
, потому что в итоговую таблицу вводятся пустые поля; На самом деле это алгоритм O(n3)! Кроме того, вы предварительно формируете его на DataTable
с помощью итерации DataRow
, которые, вероятно, неэффективны для ваших требований.
Если ваш исходный набор данных невелик (как вы упомянули) и у вас нет ограничений по памяти, я предлагаю вам организовать ожидаемый набор данных в памяти с использованием структур данных на основе индексов. Что-то вроде этого:
var arrangeDragon = new Dictionary<string, Dictionary<string, Dictionary<string, string>>>();
Дракон входит! И съедает внутреннюю for
.
for (int c = 2; c < dtImport.Columns.Count; c++) //for each date column
{
for (int r = 1; r < dtImport.Rows.Count; r++)
{
// ...
// instead of: for (int i = 0; i < dtImportParsed.Rows.Count; i++) ...
string date = dtImport.Columns[c].ColumnName.ToString().Trim();
string accountId = dtImport.Rows[r]["account_id"].ToString();
string eventName = dtImport.Rows [r]["Event Name"].ToString().Trim();
if (!arrangeDragon.ContainsKey(date))
arrangeDragon.Add(date, new Dictionary<string, Dictionary<string, string>>());
if (!arrangeDragon[date].ContainsKey(accountId))
arrangeDragon[date][accountId] = new Dictionary<string, string>();
if (!arrangeDragon[date][accountId].ContainsKey(eventName))
arrangeDragon[date][accountId][eventName] = dtImport.Rows[r][c].ToString().Trim();
// ...
}
}
Эти проверки будут выполняться за O (1) вместо O (i), поэтому общие накладные расходы уменьшатся до O (n2), что является характером итерационной таблицы :)
Также порядок получения O (1):
string data_field = arrangeDragon["1/1/2022"]["account1"]["Event1"];
Assert.AreEqual(data_field, "42");
Теперь вы можете один раз перебрать вложенные Dictionary
и построить dtImportParsed
.
Если ваш набор данных велик или памяти хоста мало, вам нужны другие решения, которые не являются вашей проблемой, как уже упоминалось;)
Удачи
Это не отвечает на вопрос, но решает проблему. Я не уверен, как вы выполняете импорт, но некоторые библиотеки Excel предоставляют доступ к функциям Excel при работе с файлом. Таким образом, можете ли вы выполнить сводную команду для файла Excel перед извлечением данных? Другой альтернативой может быть переход к базе данных и использование команды SQL Pivot.