# 機能設計書 11-relocate

## 概要

本ドキュメントは、dplyrパッケージの`relocate()`関数に関する機能設計書である。この関数は、データフレームの列の順序を変更するための機能を提供する。

### 本機能の処理概要

`relocate()`関数は、データフレーム内の列の位置を変更するための関数である。`select()`と同じ構文を使用して、列のブロックを一度に移動することができる。

**業務上の目的・背景**：データ分析において、データフレームの列の順序は可読性や作業効率に大きく影響する。特に多数の列を持つデータセットでは、関連する列を隣接させたり、重要な列を先頭に配置したりすることで、データの理解と操作が容易になる。`relocate()`は、このような列の並び替えを直感的かつ効率的に行うための機能を提供する。

**機能の利用シーン**：
- データの前処理時に、関連する変数をグループ化して配置したい場合
- 分析結果の出力前に、重要な列を先頭に移動させたい場合
- 特定の型の列（例：文字型、数値型）をまとめて移動させたい場合
- 列名を変更しながら位置を変更したい場合

**主要な処理内容**：
1. `tidyselect::eval_select()`を使用して、移動対象の列を選択
2. `.before`または`.after`引数で指定された位置を評価
3. 移動対象列以外の列を左側(lhs)と右側(rhs)に分割
4. lhs + 選択列 + rhs の順序で列を再配置
5. 列名の変更がある場合は、新しい名前を適用

**関連システム・外部連携**：dplyrパッケージ内の`select()`関数と同じtidyselect構文を使用しており、`where()`、`any_of()`、`last_col()`などのヘルパー関数と連携して動作する。

**権限による制御**：本機能はRパッケージの一部であり、特定の権限制御は存在しない。関数を呼び出す全てのユーザーが同じ機能を利用可能である。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 該当なし | - | 本機能はRライブラリ（dplyr）のため画面は存在しない |

## 機能種別

データ変換処理（列操作）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| .data | data.frame | Yes | 操作対象のデータフレーム | data.frameまたはその派生クラスであること |
| ... | tidy-select | No | 移動する列の選択。tidyselect構文をサポート | 指定された列が存在すること |
| .before | tidy-select | No | 選択した列の移動先（この列の前に配置） | .afterと同時に指定不可 |
| .after | tidy-select | No | 選択した列の移動先（この列の後に配置） | .beforeと同時に指定不可 |

### 入力データソース

- Rセッション内のdata.frame、tibble、またはその派生クラスのオブジェクト

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | 入力と同じ型 | 列の順序が変更されたデータフレーム |

### 出力先

- Rセッション内のオブジェクトとして返却

### 出力特性

- 行は影響を受けない
- 同じ列が出力に表示されるが、異なる位置に配置される（名前変更の可能性あり）
- データフレームの属性は保持される
- グループは影響を受けない

## 処理フロー

### 処理シーケンス

```
1. UseMethod("relocate")によるメソッドディスパッチ
   └─ .dataの型に応じた適切なメソッドが呼び出される
2. eval_relocate()による列位置の計算
   └─ tidyselect::eval_select()で移動対象列を選択
3. .before/.afterの検証
   └─ 両方が指定された場合はエラー
4. 移動先位置の計算
   └─ .beforeなら指定位置の前、.afterなら指定位置+1
5. 列の分割と再結合
   └─ lhs（左側）+ sel（選択列）+ rhs（右側）
6. 列名の適用と出力
   └─ 名前変更があれば適用
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[relocate呼び出し]
    B --> C[UseMethodでディスパッチ]
    C --> D[eval_relocate実行]
    D --> E{.beforeと.after両方指定?}
    E -->|Yes| F[エラー: 両方指定不可]
    E -->|No| G{.before指定?}
    G -->|Yes| H[指定位置の前を移動先に設定]
    G -->|No| I{.after指定?}
    I -->|Yes| J[指定位置の後を移動先に設定]
    I -->|No| K[先頭を移動先に設定]
    H --> L[lhs/rhsに列を分割]
    J --> L
    K --> L
    L --> M[lhs + sel + rhsで結合]
    M --> N[列名を適用]
    N --> O[結果を返却]
    O --> P[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 相互排他引数 | .beforeと.afterは同時に指定できない | 両引数が指定された場合 |
| BR-02 | デフォルト移動先 | 位置指定がない場合、列は先頭に移動 | .before/.afterともに未指定の場合 |
| BR-03 | 空選択時の動作 | .beforeの空選択は先頭への移動、.afterの空選択は末尾への移動 | 選択が空の場合 |
| BR-04 | 重複列の処理 | 同じ列が複数回選択された場合、最後のインスタンスのみ保持 | 列が複数回名前変更された場合 |

### 計算ロジック

**移動先位置の計算**:
- `.before`指定時: `where = min(選択された位置)`
- `.after`指定時: `where = max(選択された位置) + 1`
- 未指定時: `where = 1`

**列の分割**:
- `lhs = seq(1, where - 1)から選択列を除外`
- `rhs = seq(where, n)から選択列を除外`
- 最終順序 = `c(lhs, sel, rhs)`

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

該当なし（本機能はインメモリのデータフレーム操作のみ）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 引数エラー | .beforeと.afterの両方が指定された場合 | "Can't supply both `.before` and `.after`." メッセージを表示 |
| - | 選択エラー | 存在しない列が指定された場合 | tidyselectによるエラーメッセージを表示 |

### リトライ仕様

該当なし（インタラクティブな関数呼び出しのため）

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

該当なし（本機能はデータベーストランザクションを使用しない）

## パフォーマンス要件

- 入力データのサイズに比例した線形時間計算量 O(n)（nは列数）
- メモリ使用量は入力データと同程度

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

- 本機能は純粋なデータ変換操作であり、特別なセキュリティ考慮事項はない
- 入力データの内容は変更されず、列の順序のみが変更される

## 備考

- `relocate()`はdplyr 1.0.0で導入された関数
- ジェネリック関数として実装されており、他のパッケージが独自のメソッドを提供可能
- `select()`で同様の操作は可能だが、`relocate()`はより直感的で意図が明確

---

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

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

### 推奨読解順序

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

`relocate()`は入力として`data.frame`およびその派生クラスを受け取り、同じ型のオブジェクトを返す。内部では列のインデックスを整数ベクトルとして操作する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | relocate.R | `R/relocate.R` | 戻り値となる名前付き整数ベクトルの構造（81-85行目のコメント参照） |

**読解のコツ**: `eval_relocate()`は名前付き整数ベクトルを返す。各要素はデータフレームの列位置を示し、名前は新しい列名を表す。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | relocate.R | `R/relocate.R` | `relocate()`関数のジェネリック定義（49-51行目） |
| 2-2 | relocate.R | `R/relocate.R` | `relocate.data.frame()`メソッド実装（54-68行目） |

**主要処理フロー**:
1. **49-51行目**: `UseMethod("relocate")`によるジェネリック関数定義
2. **55-62行目**: `eval_relocate()`を呼び出して新しい列順序を計算
3. **64行目**: `dplyr_col_select()`で列を選択
4. **65行目**: `set_names()`で新しい列名を適用

#### Step 3: 列位置計算ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | relocate.R | `R/relocate.R` | `eval_relocate()`関数（70-169行目） |

**主要処理フロー**:
- **89-94行目**: `tidyselect::eval_select()`で移動対象列を選択
- **100-101行目**: 重複列の処理（最後のインスタンスのみ保持）
- **111-114行目**: `.before`と`.after`の同時指定チェック
- **116-153行目**: 移動先位置（where）の計算
- **155-166行目**: lhs、rhs、selの結合による最終順序の生成

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

```
relocate(.data, ..., .before, .after)
    │
    ├─ UseMethod("relocate")
    │      │
    │      └─ relocate.data.frame()
    │             │
    │             ├─ eval_relocate()
    │             │      │
    │             │      ├─ tidyselect::eval_select() [移動列選択]
    │             │      │
    │             │      ├─ as_quosure() [.before/.after処理]
    │             │      │
    │             │      ├─ tidyselect::eval_select() [位置選択]
    │             │      │
    │             │      └─ vec_c() [列順序結合]
    │             │
    │             ├─ dplyr_col_select() [列選択実行]
    │             │
    │             └─ set_names() [列名適用]
```

### データフロー図

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

.data ─────────────────┬─ eval_relocate() ─────────────── 列順序(整数ベクトル)
                       │         │
... (列選択) ──────────┤         ├─ tidyselect評価
                       │         │
.before/.after ────────┘         └─ 位置計算
                                         │
                                         ▼
                                 dplyr_col_select()
                                         │
                                         ▼
                                    set_names()
                                         │
                                         ▼
                                [並び替え済みdata.frame]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| relocate.R | `R/relocate.R` | ソース | relocate関数のメイン実装 |
| generics.R | `R/generics.R` | ソース | dplyr汎用関数の定義 |
| test-relocate.R | `tests/testthat/test-relocate.R` | テスト | relocateのユニットテスト |
