# 機能設計書 31-bind_cols

## 概要

本ドキュメントは、dplyrパッケージの `bind_cols()` 関数の機能設計を記述する。この関数は複数のデータフレームを列方向に結合し、より幅広い結果を生成する。

### 本機能の処理概要

`bind_cols()` は、任意の数のデータフレームを列方向（横方向）に結合し、各入力の列をすべて含む新しいデータフレームを返す関数である。これは `do.call(cbind, dfs)` と類似しているが、より安全で一貫した動作を提供する。

**業務上の目的・背景**：データ分析において、異なるソースから取得した関連データや、別々に計算された結果を1つのデータフレームに統合する必要がある。例えば、顧客の基本情報と購買履歴を横に並べて分析したい場合や、機械学習の特徴量を段階的に追加したい場合などに使用される。`bind_cols()` は行の順序に基づいて結合するため、位置ベースの単純な列統合が必要な場面で活用される。

**機能の利用シーン**：
- 別々のデータソースから取得したデータの横方向統合
- 計算結果（予測値、残差など）を元データに追加する場合
- 複数の特徴量テーブルを1つに統合する場合
- 中間計算結果を段階的に蓄積する場合

**主要な処理内容**：
1. 入力引数を `list2()` で取得し、ネストされたリストを `list_flatten()` で平坦化
2. NULL要素を `discard()` で除去
3. データフレームコンポーネントの名前を削除して `vec_cbind()` がアンパックするように設定
4. `vctrs::vec_cbind()` を使用して列方向の結合を実行
5. 入力にデータフレームが含まれない場合はtibbleに変換
6. 最初のデータフレームの型を保持するために `dplyr_reconstruct()` を適用

**関連システム・外部連携**：vctrパッケージの `vec_cbind()` 関数に依存している。入力はリサイクル規則に従って同じ長さに調整される。

**権限による制御**：特になし。すべてのユーザーが利用可能。

## 関連画面

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

## 機能種別

データ操作 / 結合処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| ... | データフレームまたはリスト | Yes | 結合するデータフレーム。各引数はデータフレーム、データフレームになり得るリスト、またはデータフレームのリストが可能 | 行数が互換性を持つ必要がある（リサイクル可能） |
| .name_repair | character | No | 列名の修復方法。"unique"、"universal"、"check_unique"、"minimal"のいずれか。デフォルトは"unique" | 指定された値のいずれかである必要がある |

### 入力データソース

プログラムからの直接入力（データフレームオブジェクト）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| (返り値) | data.frame / tibble | 入力データフレームのすべての列を含む、列方向に結合されたデータフレーム。型は最初の入力要素の型を継承する |

### 出力先

呼び出し元への戻り値として返却

## 処理フロー

### 処理シーケンス

```
1. 引数の収集
   └─ list2(...)で引数を収集

2. リストの平坦化
   └─ list_flatten()でネストを解消（recursive = TRUE）

3. NULL要素の除去
   └─ discard()でNULL要素をフィルタリング

4. データフレームの名前削除
   └─ データフレームコンポーネントの名前を空文字に設定
   └─ vec_cbind()がアンパックできるようにする

5. 列結合の実行
   └─ vec_cbind()で列方向結合
   └─ .name_repairオプションを適用

6. 型の調整
   └─ データフレームがない場合はas_tibble()で変換
   └─ 最初のデータフレームの型を保持（dplyr_reconstruct）

7. 結果の返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[引数をlist2で収集]
    B --> C[list_flattenでネスト解消]
    C --> D[NULLを除去]
    D --> E[データフレームの名前を削除]
    E --> F[vec_cbindで列結合]
    F --> G{データフレームが含まれるか}
    G -->|No| H[tibbleに変換]
    G -->|Yes| I{最初の要素がデータフレームか}
    H --> J[結果を返却]
    I -->|Yes| K[dplyr_reconstructで型を保持]
    I -->|No| J
    K --> J
    J --> L[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-31-01 | 行数の互換性 | 入力データフレームの行数は互換性を持つ必要がある（リサイクル可能） | 常時 |
| BR-31-02 | 位置ベース結合 | 行は出現順序に従って結合される（キーによる結合ではない） | 常時 |
| BR-31-03 | 型の継承 | 出力データフレームは最初の入力データフレームの型を継承する | 最初の入力がデータフレームの場合 |
| BR-31-04 | 列名の一意性 | デフォルトで列名は一意になるように修復される | .name_repair = "unique"の場合 |

### 計算ロジック

特になし（列の結合のみ）

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

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 行数不一致エラー | 入力データフレームの行数が互換性を持たない場合 | 同じ行数のデータフレームを使用するか、リサイクル可能な行数にする |
| - | 列名重複エラー | .name_repair = "check_unique"で列名が重複する場合 | 事前に列名を変更するか、別の.name_repairオプションを使用 |

### リトライ仕様

該当なし（同期処理）

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

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

## パフォーマンス要件

特に定義なし。vctrパッケージの最適化された実装に依存。

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

特になし

## 備考

- 可能な場合は `join` 系関数（`left_join` など）の使用が推奨される
- `bind_cols()` は行の順序に基づいて結合するため、意図しない結果を生みやすい
- 結合前にデータの順序が正しいことを確認することが重要

---

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

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

### 推奨読解順序

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

vctrパッケージの型システムとリサイクル規則を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | vec_cbind() | vctrsパッケージ | 列結合の基本動作とリサイクル規則 |

**読解のコツ**: vctrパッケージの `vec_cbind()` は入力をリサイクルして同じ長さに調整する。データフレームの名前が空の場合、列がアンパックされる。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | bind-cols.R | `R/bind-cols.R` | bind_cols関数の定義（27-51行目） |

**主要処理フロー**:
1. **31行目**: `list2(...)` で引数を収集
2. **33行目**: `list_flatten()` でネストを解消
3. **34行目**: `discard()` でNULL要素を除去
4. **37行目**: データフレームの名前を空文字に設定
5. **39-43行目**: `vec_cbind()` で列結合を実行
6. **44-46行目**: データフレームがない場合はtibbleに変換
7. **47-49行目**: 最初のデータフレームの型を保持

#### Step 3: ヘルパー関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | grouped-df.R | `R/grouped-df.R` | dplyr_reconstruct関数の実装 |

**主要処理フロー**:
- `dplyr_reconstruct()`: 出力データフレームの型を入力の型に合わせて再構築

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

```
bind_cols()
    │
    ├─ list2()                     [rlang]
    │
    ├─ list_flatten()              [rlang]
    │
    ├─ discard()                   [purrr]
    │
    ├─ vec_cbind()                 [vctrs]
    │      └─ リサイクル処理
    │      └─ 列名修復処理
    │
    ├─ as_tibble()                 [tibble] (必要な場合)
    │
    └─ dplyr_reconstruct()         [dplyr]
```

### データフロー図

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

データフレーム1 ─┐
                 │
データフレーム2 ─┼───▶ bind_cols() ───▶ 結合されたデータフレーム
                 │     (vec_cbind)
データフレームN ─┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| bind-cols.R | `R/bind-cols.R` | ソース | bind_cols関数のメイン実装 |
| grouped-df.R | `R/grouped-df.R` | ソース | dplyr_reconstruct関数を含む |
| reexport-tibble.R | `R/reexport-tibble.R` | ソース | tibble関連のre-export |
