# 機能設計書 45-replace_when

## 概要

本ドキュメントは、dplyrパッケージの`replace_when()`関数の機能設計について記述する。`replace_when()`は条件に基づいて既存ベクトルの値を部分的に更新する関数であり、`case_when()`と異なり元の値を保持しつつ条件に一致する要素のみを置換する。

### 本機能の処理概要

`replace_when()`は、入力ベクトル`x`に対して、指定した条件に一致する要素のみを新しい値で置換し、一致しない要素は元の値を保持する関数である。`case_when()`が完全に新しいベクトルを生成するのに対し、`replace_when()`は既存ベクトルの部分的な更新に特化している。これにより型安定性が保証され、意図がより明確に表現できる。

**業務上の目的・背景**：データクレンジングやデータ変換において、ベクトルの一部の値のみを条件に基づいて更新したい場面は頻繁に発生する。従来の`case_when(x, condition ~ new_value, .default = x)`という書き方は冗長で、意図が不明確になりがちである。`replace_when()`は「既存の値を部分的に更新する」という意図を明確に表現でき、型安定性も保証されるため、より安全で可読性の高いコードが書ける。

**機能の利用シーン**：
- 特定条件に一致するデータのみを修正する場合
- 外れ値やエラー値の条件付き修正
- 複数条件に基づく段階的なデータ更新
- `NA`値の条件付き置換

**主要な処理内容**：
1. フォーミュラを解析してLHS（条件）とRHS（値）を抽出する
2. 各条件を順次評価する
3. 条件に一致する要素のみを対応する値で置換する
4. 一致しない要素は元の値を保持する
5. 結果ベクトルを返す

**関連システム・外部連携**：vctrsパッケージの`vec_replace_when()`を内部で使用する。

**権限による制御**：特になし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 該当なし | - | 本プロジェクトはRライブラリであり、ユーザーインターフェース画面は存在しない |

## 機能種別

計算処理 / データ変換 / 条件分岐

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| x | any | Yes | 更新対象のベクトル | ベクトルであること |
| ... | formula | No | `condition ~ value`形式の二項フォーミュラ。NULLは無視される | 二項フォーミュラであること |

### 入力データソース

関数の引数として直接渡されるベクトルとフォーミュラ

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| result | any | xと同じサイズ、同じ型を持つ更新されたベクトル |

### 出力先

呼び出し元に返される。

## 処理フロー

### 処理シーケンス

```
1. 引数の検証
   └─ check_dots_unnamed()で名前付き引数をチェック
2. フォーミュラの解析
   └─ eval_formulas()で...を解析
   └─ LHS（conditions）とRHS（values）を分離
3. vctrs::vec_replace_when()の呼び出し
   └─ x, conditions, valuesを渡す
   └─ 型はxに固定（型安定）
4. 結果ベクトルを返す
   └─ サイズ、型、名前はxと同一
```

### フローチャート

```mermaid
flowchart TD
    A[開始: replace_when呼び出し] --> B[check_dots_unnamed で引数検証]
    B --> C[eval_formulas で...を解析]
    C --> D{フォーミュラがあるか?}
    D -->|No| E[xをそのまま返す]
    D -->|Yes| F[LHSとRHSを分離]
    F --> G[vec_replace_when を呼び出し]
    G --> H{各要素を評価}
    H --> I{条件に一致?}
    I -->|Yes| J[対応する値で置換]
    I -->|No| K[元の値を保持]
    J --> L[結果ベクトルを返す]
    K --> L
    E --> M[終了]
    L --> M
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-45-01 | 型安定性 | 出力はxと同じ型。RHSはxの型にキャストされる | 常に適用 |
| BR-45-02 | サイズ安定性 | 出力はxと同じサイズ | 常に適用 |
| BR-45-03 | 名前保持 | 出力はxの名前を保持する | 常に適用 |
| BR-45-04 | 順次評価 | 条件は上から順に評価され、最初に一致した条件が使用される | 常に適用 |
| BR-45-05 | 元値保持 | 一致しない要素は元の値xを保持する | 常に適用 |
| BR-45-06 | 空フォーミュラ | フォーミュラが空の場合はxをそのまま返す | ...が空の場合 |

### 計算ロジック

```
result = x (初期値)
for each j in 1:n_conditions:
    for each i where conditions[j][i] == TRUE and not yet matched:
        result[i] = cast(values[j][i], to = type(x))
```

## データベース操作仕様

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| - | - | - | 本関数はインメモリ操作のみでデータベース操作を行わない |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | フォーミュラエラー | 二項フォーミュラでない場合 | `condition ~ value`形式を使用する |
| - | 型エラー | LHSが論理型でない場合 | 論理式を使用する |
| - | サイズエラー | LHSがxと異なるサイズの場合 | xと同じサイズの条件を使用する |
| - | 型変換エラー | RHSがxの型にキャストできない場合 | 互換性のある値を使用する |

### リトライ仕様

リトライは不要（即座にエラーを返す）

## トランザクション仕様

該当なし（インメモリ操作のみ）

## パフォーマンス要件

- vctrsの効率的な実装を活用すること
- フォーミュラが空の場合は即座にxを返すこと

## セキュリティ考慮事項

特になし

## 備考

- `replace_when()`は`case_when()`の部分更新版である
- `case_when(x, condition ~ value, .default = x)`と同等だが、より簡潔で意図が明確
- 型安定性が保証されるため、因子型などの特殊な型でも安全に使用できる
- `pick()`と組み合わせて複数列を同時に更新することも可能

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

`replace_when()`は型安定性を保証するシンプルな関数である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | case-when.R | `R/case-when.R` | `replace_when()`関数の全体構造を理解する |

**読解のコツ**: `replace_when()`は`case_when()`と同じファイルで定義されているが、型安定性の点で異なる動作をする。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | case-when.R | `R/case-when.R` | 326-342行目の`replace_when()`関数定義 |

**主要処理フロー**:
1. **327行目**: `check_dots_unnamed()` - 名前付き引数のチェック
2. **329行目**: `eval_formulas()`でフォーミュラを解析（allow_empty_dots = TRUE）
3. **330-331行目**: LHS（conditions）とRHS（values）を取得
4. **333-341行目**: `vec_replace_when()`を呼び出し

#### Step 3: case_when()との違いを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | case-when.R | `R/case-when.R` | 1-23行目のドキュメント |

**読解のコツ**: ドキュメントの冒頭で`case_when()`と`replace_when()`の違いが明確に説明されている。特に「一致しない場合の動作」の違いに注目。

#### Step 4: 使用例を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | case-when.R | `R/case-when.R` | 188-222行目の使用例 |

**読解のコツ**: petsデータフレームの例で、因子型の型安定性が示されている。

### プログラム呼び出し階層図

```
replace_when(x, ...)
    │
    ├─ check_dots_unnamed() [引数検証]
    │
    ├─ eval_formulas(...)
    │      ├─ validate_and_split_formula()
    │      └─ eval_tidy() [LHS/RHSの評価]
    │
    └─ vctrs::vec_replace_when()
           ├─ 条件の順次評価
           ├─ 一致した要素を値で置換
           └─ 一致しない要素は元の値を保持
```

### データフロー図

```
[入力]                    [処理]                           [出力]

x (ベクトル)       ───▶  デフォルト出力として保持    ───▶  result (初期値)

...フォーミュラ    ───▶  eval_formulas()で解析      ───▶  conditions, values
  (condition ~ value)

conditions         ───▶  各条件を評価               ───▶  一致インデックス

values             ───▶  xの型にキャスト            ───▶  キャスト済み値

一致インデックス   ───▶  一致位置を値で置換         ───▶  更新されたresult
  + キャスト済み値
  + result
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| case-when.R | `R/case-when.R` | ソース | `replace_when()`、`case_when()`の実装 |
| recode-values.R | `R/recode-values.R` | ソース | `replace_values()`関数（値マッチングによる置換） |
| coalesce.R | `R/coalesce.R` | ソース | `coalesce()`関数（NA置換の代替） |
