# 機能設計書 35-setdiff

## 概要

本ドキュメントは、dplyrパッケージの `setdiff()` 関数の機能設計を記述する。この関数は最初のデータフレームから2番目のデータフレームに存在する行を除いた差集合を取得する集合演算関数である。

### 本機能の処理概要

`setdiff()` は、データフレーム x に存在するが y には存在しない行のみを抽出し、新しいデータフレームを返す関数である。SQLの EXCEPT 演算に相当する操作を提供する。

**業務上の目的・背景**：データ分析において、あるデータセットから別のデータセットに含まれるレコードを除外する必要がある場面は多い。例えば、既存顧客リストから新規顧客を除外して既存顧客のみを抽出、除外リストに含まれるレコードの削除、2つの期間のデータの差分検出などに使用される。`setdiff()` は、base Rの同名関数をジェネリック関数として拡張し、データフレームに対しても適用可能にしている。

**機能の利用シーン**：
- 既存データから特定条件のデータを除外
- マスターデータから削除対象を特定
- 2つのデータセットの差分検出
- 前回処理済みデータの除外

**主要な処理内容**：
1. `check_dots_empty()` で追加引数がないことを確認
2. `check_compatible()` で2つのデータフレームの互換性を検証
3. `vctrs::vec_set_difference()` を使用して差集合を計算
4. `dplyr_reconstruct()` で元のデータフレーム型を保持

**関連システム・外部連携**：genericsパッケージからインポートされたジェネリック関数として実装。vctrパッケージの `vec_set_difference()` に依存。

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

## 関連画面

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

## 機能種別

データ操作 / 集合演算

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| x | data.frame | Yes | 最初のデータフレーム（差集合の基準） | データフレームである必要がある |
| y | data.frame | Yes | 2番目のデータフレーム（除外対象） | xと互換性のあるデータフレームである必要がある |
| ... | (空) | No | 使用されない。空であることが必須 | check_dots_empty()でチェック |

### 入力データソース

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

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| (返り値) | data.frame | xに存在するがyには存在しない行を含むデータフレーム。x自体の重複行も除去される。型はxを継承する |

### 出力先

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

## 処理フロー

### 処理シーケンス

```
1. ドット引数の検証
   └─ check_dots_empty()で追加引数がないことを確認

2. 互換性チェック
   └─ check_compatible()でxとyの列名・型の互換性を検証

3. 差集合の計算
   └─ vec_set_difference()でxにのみ存在する行を抽出
   └─ x自体の重複行も除去される

4. 型の再構築
   └─ dplyr_reconstruct()でxの型を保持

5. 結果の返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[check_dots_empty]
    B --> C[check_compatible x, y]
    C --> D{互換性あり?}
    D -->|No| E[エラー: 互換性なし]
    D -->|Yes| F[vec_set_difference]
    F --> G[dplyr_reconstruct]
    G --> H[結果を返却]
    H --> I[終了]
    E --> I
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-35-01 | 互換性要件 | xとyは同じ列名（順序は異なっても可）と互換性のある型を持つ必要がある | 常時 |
| BR-35-02 | 重複除去 | x自体の重複行も結果から除去される | 常時 |
| BR-35-03 | 非対称性 | setdiff(x, y)とsetdiff(y, x)は異なる結果を返す | 常時 |
| BR-35-04 | 型の継承 | 出力データフレームはxの型を継承する | 常時 |

### 計算ロジック

集合論の差集合: `x \ y = {e | e ∈ x かつ e ∉ y}`

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

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 互換性エラー | yがデータフレームでない場合 | データフレームを渡す |
| - | 列数不一致エラー | xとyの列数が異なる場合 | 同じ列数のデータフレームを使用 |
| - | 列名不一致エラー | xとyの列名が一致しない場合 | 同じ列名を持つデータフレームを使用 |
| - | 型不一致エラー | 同名の列で型が互換性を持たない場合 | 型を揃えてから実行 |
| - | ドット引数エラー | ...に引数が渡された場合 | 追加引数を削除 |

### リトライ仕様

該当なし（同期処理）

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

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

## パフォーマンス要件

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

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

特になし

## 備考

- base Rの `setdiff()` をジェネリック関数として拡張している
- 既存のベクター向け動作はデフォルトメソッドで保持される
- 集合演算のため、結果の行順序は保証されない
- `setdiff(x, y)` と `setdiff(y, x)` は異なる結果になる（非対称演算）

---

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

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

### 推奨読解順序

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

互換性チェックのロジックを理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | sets.R | `R/sets.R` | is_compatible関数（162-241行目）の互換性チェックロジック |

**読解のコツ**: `is_compatible()` 関数は列数、列名、列の型を順番にチェックする。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | sets.R | `R/sets.R` | setdiff.data.frame メソッド（132-139行目） |

**主要処理フロー**:
1. **133行目**: `check_dots_empty()` で追加引数がないことを確認
2. **134行目**: `check_compatible(x, y)` で互換性を検証
3. **136行目**: `vec_set_difference(x, y)` で差集合を計算
4. **138行目**: `dplyr_reconstruct(out, x)` で型を保持

#### Step 3: 関連する集合演算との比較

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | sets.R | `R/sets.R` | symdiff.data.frame（151-158行目）との違い |

**比較ポイント**:
- `setdiff(x, y)`: xにのみ存在する行
- `symdiff(x, y)`: xまたはyの一方にのみ存在する行（対称差）

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

```
setdiff(x, y, ...)
    │
    ├─ setdiff.data.frame()       [dplyr]
    │      │
    │      ├─ check_dots_empty()  [rlang]
    │      │
    │      ├─ check_compatible()  [dplyr]
    │      │      │
    │      │      └─ is_compatible()
    │      │
    │      ├─ vec_set_difference() [vctrs]
    │      │
    │      └─ dplyr_reconstruct() [dplyr]
    │
    └─ setdiff.default()          [base] (ベクター用)
```

### データフロー図

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

データフレーム x ─┐
                  │
                  ├───▶ setdiff() ───▶ xにのみ存在する行
                  │     (vec_set_difference)
データフレーム y ─┘

例:
x = {A, B, C, D}
y = {C, D, E}
setdiff(x, y) = {A, B}
setdiff(y, x) = {E}  ← 非対称であることに注意
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| sets.R | `R/sets.R` | ソース | setdiff.data.frame実装、互換性チェック |
| generics.R | `R/generics.R` | ソース | ジェネリック関数のインポート |
| grouped-df.R | `R/grouped-df.R` | ソース | dplyr_reconstruct関数 |
