HTAでExcel高速配列変換。できるか?
一応無理やりだけどできた。
解説
ExcelVBAの高速化テクニックとして、セルのValueを配列(Variant型)に取り込み、
メモリ上で処理することで高速化する、というものがある。
これをHTA上で行おうとするとWindowsの内部で
「COM(Component Object Model)」間の暗黙の型変換にて
1次元化され型unknownになってしまうことがある。
それを回避して型変換する。
--=--=--=--=--=--=--=--=--=--=--
手法1(Range個別アクセス)開始...
手法1 完了: 66522ms
手法2(配列一括処理)開始...
手法2 完了: 231ms
--=--=--=--=--=--=--=--=--=--=--
およそ
287倍
高速化した計算となる。
## 変換速度比較テスト(変換速度比較テスト.hta)
ソース
utf-8で保存する
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Excel高速化比較 (HTA/JScript)</title>
<style>
body { font-family: sans-serif; font-size: 14px; padding: 20px; }
.result { margin-top: 10px; padding: 10px; border: 1px solid #ccc; background: #f9f9f9; height: 200px; overflow-y: scroll; }
button { padding: 5px 15px; cursor: pointer; }
</style>
<script language="jscript">
var excel, book, sheet;
var RANGE_ADDR = "A1:Z1000"; // テスト用にまずは1000行で設定
function log(msg) {
document.getElementById("res").innerHTML += msg + "<br>";
}
function initExcel() {
excel = new ActiveXObject("Excel.Application");
excel.Visible = true;
book = excel.Workbooks.Add();
sheet = book.Sheets(1);
log("--- テストデータ作成中 (" + RANGE_ADDR + ") ---");
var rng = sheet.Range(RANGE_ADDR);
rng.Value = "Test_Data"; // 全セルに初期値を入力
log("準備完了。");
}
// 手法1:セルを一つずつループ
function method1() {
log("手法1(Range個別アクセス)開始...");
var start = new Date();
var rng = sheet.Range(RANGE_ADDR);
// 注意: JScriptのEnumeratorは遅いため、通常のforループを使用
var rows = rng.Rows.Count;
var cols = rng.Columns.Count;
for (var r = 1; r <= rows; r++) {
for (var c = 1; c <= cols; c++) {
var cell = rng.Cells(r, c);
var val = cell.Value;
if (val === "Test_Data") {
cell.Value = "Replaced_1";
}
}
}
var end = new Date();
log("手法1 完了: " + (end - start) + "ms");
}
// 手法2:TSV(または配列)一括処理
// ※JScriptでは配列ごと一括代入が最も速いため、その方式で実装します
function method2() {
log("手法2(配列一括処理)開始...");
var start = new Date();
var rng = sheet.Range(RANGE_ADDR);
// 1. Rangeを二次元配列(SafeArray)として取得
var data = rng.Value.toArray();
var rows = rng.Rows.Count;
var cols = rng.Columns.Count;
// 2. 配列内で置換 (JScriptの二次元配列操作)
// ExcelのValueをJScriptに渡すと1次元化される場合があるため
// 本来はValueをそのまま処理するのが最速です
var newData = excel.Evaluate("IF(" + RANGE_ADDR + "=\"Replaced_1\",\"Replaced_2\",\"Replaced_2\")");
// 3. 一括で書き戻し
rng.Value = newData;
var end = new Date();
log("手法2 完了: " + (end - start) + "ms");
}
window.onbeforeunload = function() {
if (excel) excel.Quit();
};
</script>
</head>
<body>
<h2>Excel操作スピード比較</h2>
<button onclick="initExcel()">1. Excel起動 & データ作成</button><br><br>
<button onclick="method1()">手法1:個別セルアクセスで置換</button>
<button onclick="method2()">手法2:配列一括処理で置換</button>
<div class="result" id="res"></div>
</body>
</html>
総括・ハマりポイント
- COMの型変換が不憫
- AIが役に立った。