テーマの整理:「欠損補完」とは何か
ここでの「欠損補完」は、配列の中にある「抜けている値・足りないレコード」を、一定のルールで埋めるユーティリティのことです。 業務だと、次のような場面でよく出てきます。
- 日別データで「ある日だけレコードがない」ので、0 や前日値で埋めたい。
- 数値配列の中に null や undefined が混ざっていて、計算前に補完したい。
- 時系列データで「間の時間が抜けている」ので、連続した系列にしたい。
「欠損があるのは現実」で、「それをどう埋めるか」が欠損補完の仕事です。
基本コンセプト:「抜けているところを、ルールに従って埋める」
欠損の種類をざっくりイメージする
配列の欠損には、ざっくり次のようなパターンがあります。
- 値があるべき場所に null や undefined が入っている。
- 本来あるべきキー(例: 特定の日付)のレコード自体が存在しない。
- 数値が入るべきところに空文字や不正値が入っていて、実質的に欠損になっている。
欠損補完ユーティリティは、 「どこを欠損とみなすか」「どういう値で埋めるか」を決めて、配列を“扱いやすい状態”にするためのものです。
ユーティリティ 1:数値配列の欠損を「固定値」で補完する
シナリオ
次のような配列があるとします。
const raw = [10, null, 20, undefined, 30];
JavaScriptここから、
- null や undefined を「0」で埋めたい。
という欠損補完をしたいとします。
実装:fillMissingWithValue
function fillMissingWithValue(array, fillValue) {
if (!Array.isArray(array)) {
return [];
}
return array.map((v) => (v == null ? fillValue : v));
}
JavaScript重要ポイントをかみ砕いて説明
まず「配列かどうか」をチェックし、配列でなければ空配列を返します。 v == null は、null と undefined の両方を「欠損」とみなす書き方です。 欠損なら fillValue を入れ、それ以外なら元の値をそのまま返します。
これで、「欠損を特定の値で埋めた配列」が手に入ります。
例題 1:null と undefined を 0 で補完する
const raw = [10, null, 20, undefined, 30];
const filled = fillMissingWithValue(raw, 0);
console.log(filled);
JavaScript出力イメージはこうなります。
[10, 0, 20, 0, 30]
JavaScriptこの「欠損補完済みの配列」を使えば、 合計や平均などの計算をするときに、毎回 null チェックをしなくて済みます。
ユーティリティ 2:数値配列の欠損を「前の値」で補完する(前方補完)
シナリオ
次のような時系列データがあるとします。
const raw = [100, null, null, 130, null, 150];
JavaScriptここから、
- 欠損を「直前の値」で埋めたい(前方補完)。
という欠損補完をしたいとします。
実装:fillMissingForward
function fillMissingForward(array) {
if (!Array.isArray(array)) {
return [];
}
let lastValue = null;
return array.map((v) => {
if (v == null) {
return lastValue;
} else {
lastValue = v;
return v;
}
});
}
JavaScript重要ポイントをかみ砕いて説明
lastValue に「直前の有効な値」を覚えておきます。 値が欠損(null / undefined)のときは、lastValue を返します。 値が有効なときは、その値を返しつつ、lastValue を更新します。
これで、「最初の有効値以降の欠損」が、直前の値で埋められます。
例題 2:前方補完で時系列の欠損を埋める
const raw = [100, null, null, 130, null, 150];
const filled = fillMissingForward(raw);
console.log(filled);
JavaScript出力イメージはこうなります。
[100, 100, 100, 130, 130, 150]
JavaScriptここでのポイントは、
- 2 番目と 3 番目の null が「100」で埋まっている。
- 5 番目の null が「130」で埋まっている。
というところです。
時系列データでは、「直前の値で補完する」ことがよくあります。 このユーティリティを持っておくと、そのパターンを簡単に書けます。
ユーティリティ 3:日付系列の「抜けている日」を補完する
シナリオ
次のような日別売上データがあるとします。
const sales = [
{ date: "2024-07-01", amount: 100 },
{ date: "2024-07-03", amount: 200 },
];
JavaScriptここで、「2024-07-02 のレコードがない」という欠損があります。 これを、
- 連続した日付系列にしたい。
- 欠損日の amount は 0 で埋めたい。
という欠損補完をしたいとします。
日付を 1 日進めるヘルパー
function addDays(dateStr, days) {
const d = new Date(dateStr);
d.setDate(d.getDate() + days);
const yyyy = d.getFullYear();
const mm = String(d.getMonth() + 1).padStart(2, "0");
const dd = String(d.getDate()).padStart(2, "0");
return `${yyyy}-${mm}-${dd}`;
}
JavaScript実装:fillMissingDates
function fillMissingDates(records, startDate, endDate) {
const map = new Map();
records.forEach((r) => {
map.set(r.date, r.amount);
});
const result = [];
let current = startDate;
while (current <= endDate) {
const amount = map.has(current) ? map.get(current) : 0;
result.push({ date: current, amount });
current = addDays(current, 1);
}
return result;
}
JavaScript重要ポイントをかみ砕いて説明
まず records を Map に入れて、「日付 → amount」の対応を作ります。 startDate から endDate まで 1 日ずつ進めながら、 その日付が Map にあれば元の amount を、なければ 0 を使います。 こうして、「連続した日付系列+欠損日の 0 補完」の配列を作ります。
例題 3:抜けている日付を 0 で補完する
const sales = [
{ date: "2024-07-01", amount: 100 },
{ date: "2024-07-03", amount: 200 },
];
const filled = fillMissingDates(sales, "2024-07-01", "2024-07-03");
console.log(filled);
JavaScript出力イメージはこうなります。
[
{ date: "2024-07-01", amount: 100 },
{ date: "2024-07-02", amount: 0 },
{ date: "2024-07-03", amount: 200 },
]
JavaScriptここでのポイントは、
- 「日付の欠損」を「レコード自体を追加する」ことで補完している。
- 欠損日の amount を 0 にするルールが、ユーティリティに閉じ込められている。
というところです。
業務では、「抜けている日・時間・ID を補完して連続系列にする」ことがよくあるので、 このパターンはかなり実用的です。
欠損補完ユーティリティで意識してほしい重要ポイント
「何を欠損とみなすか」「何で埋めるか」をはっきり決める
欠損補完は、ルールを決めないと危ない処理です。
- null と undefined だけを欠損とみなすのか。
- 空文字や 0 も欠損とみなすのか。
- 補完値は 0 なのか、前の値なのか、平均なのか。
ここを曖昧にしたまま補完すると、 「本当は意味のある 0 まで消してしまう」などの事故につながります。
初心者のうちは、
- 「欠損=null / undefined」とまずは決める。
- 補完値は「0」か「前の値」のどちらかから始める。
くらいで十分です。 慣れてきたら、業務仕様に合わせてルールを増やしていくイメージを持つとよいです。
「補完したことが分かるようにしておく」ことも大事
場合によっては、「どこが元データで、どこが補完された値か」を区別したくなることがあります。 そのときは、レコードにフラグを持たせるのも一つの手です。
例えば、fillMissingDates を少し変えて、
result.push({
date: current,
amount,
filled: !map.has(current), // 補完された行なら true
});
JavaScriptのようにしておくと、
- グラフでは補完値を薄い色で表示する。
- レポートでは「補完値が含まれている」ことを注記する。
といった工夫がしやすくなります。
手を動かして「欠損補完」の感覚をつかむ
次のコードを実行して、
- 固定値補完
- 前方補完
- 日付欠損補完
の 3 パターンを体感してみてください。
function fillMissingWithValue(array, fillValue) {
if (!Array.isArray(array)) {
return [];
}
return array.map((v) => (v == null ? fillValue : v));
}
function fillMissingForward(array) {
if (!Array.isArray(array)) {
return [];
}
let lastValue = null;
return array.map((v) => {
if (v == null) {
return lastValue;
} else {
lastValue = v;
return v;
}
});
}
function addDays(dateStr, days) {
const d = new Date(dateStr);
d.setDate(d.getDate() + days);
const yyyy = d.getFullYear();
const mm = String(d.getMonth() + 1).padStart(2, "0");
const dd = String(d.getDate()).padStart(2, "0");
return `${yyyy}-${mm}-${dd}`;
}
function fillMissingDates(records, startDate, endDate) {
const map = new Map();
records.forEach((r) => {
map.set(r.date, r.amount);
});
const result = [];
let current = startDate;
while (current <= endDate) {
const amount = map.has(current) ? map.get(current) : 0;
result.push({ date: current, amount });
current = addDays(current, 1);
}
return result;
}
function demo() {
console.log("=== fillMissingWithValue ===");
console.log(fillMissingWithValue([10, null, 20, undefined, 30], 0));
console.log("=== fillMissingForward ===");
console.log(fillMissingForward([100, null, null, 130, null, 150]));
console.log("=== fillMissingDates ===");
console.log(
fillMissingDates(
[
{ date: "2024-07-01", amount: 100 },
{ date: "2024-07-03", amount: 200 },
],
"2024-07-01",
"2024-07-03"
)
);
}
demo();
JavaScriptまとめ:欠損補完ユーティリティで「穴だらけの現実データを、扱える形にする」
欠損補完は、 「現実のデータに必ず存在する“穴”を、ルールに従って埋めて、配列を扱いやすくするためのユーティリティ」です。
プロジェクトに例えば次のような形で置いておくイメージです。
export function fillMissingWithValue(array, fillValue) { ... }
export function fillMissingForward(array) { ... }
export function fillMissingDates(records, startDate, endDate) { ... }
JavaScriptそして、
- 集計前
- グラフ描画前
- レポート生成前
など、「欠損があると困る処理」の前で必ずこの欠損補完を通す。
こう決めておくと、 配列データが「穴だらけの現実」から「扱いやすい形」に変わり、 業務ロジックがぐっと安定して動くようになります。
欠損は避けられないけれど、 どう埋めるかは、あなたが決められる。 その決め方をコードに落としたものが、欠損補完ユーティリティです。
