# 機能設計書 89-unique

## 概要

本ドキュメントは、Hack Standard Library (HSL) の Dict モジュールにおける `unique` 関数の機能設計を記述する。この関数は、各値が1回のみ出現する新しい dict を返す機能を提供する。重複する値がある場合、後のキーが優先される。

### 本機能の処理概要

**業務上の目的・背景**：データ処理において、重複する値を除去して一意の値のみを保持したいケースは多い。例えば、重複するユーザーIDを除去する、一意のカテゴリリストを取得する、重複するエントリを統合するなどである。本関数は、このような重複除去を効率的に行うためのユーティリティを提供する。重要な特徴として、重複がある場合は後に出現したキーが保持される。

**機能の利用シーン**：
- 重複する値を持つエントリを除去する場合
- 一意の値のセットを取得する場合
- 最新のエントリを優先して重複を解決する場合（後のキーが優先）
- データの正規化処理で重複を除去する場合

**主要な処理内容**：
1. 入力の KeyedTraversable を flip 関数で値とキーを入れ替え（dict<Tv, Tk> を生成）
2. 再度 flip 関数で値とキーを入れ替え（dict<Tk, Tv> に戻す）
3. この二重フリップにより、重複する値は後のキーのみが残る
4. 結果の dict を返却

**関連システム・外部連携**：本関数は純粋な計算処理であり、外部システムとの連携はない。

**権限による制御**：本関数は汎用ユーティリティであり、権限による制御は行わない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 該当なし | - | 本プロジェクトはUIを持たないライブラリのため画面なし |

## 機能種別

計算処理（重複除去）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| $traversable | KeyedTraversable<Tk, Tv> | Yes | 重複除去対象の KeyedTraversable。Tv は arraykey の制約がある | なし |

### 入力データソース

関数引数として直接渡される KeyedTraversable オブジェクト。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | dict<Tk, Tv> | 各値が1回のみ出現する dict。重複時は後のキーが優先 |

### 出力先

関数の戻り値として呼び出し元に返却。

## 処理フロー

### 処理シーケンス

```
1. 第一フリップ
   └─ flip($traversable) で dict<Tv, Tk> を生成
       └─ 重複する値がある場合、後のキーで上書き
2. 第二フリップ
   └─ flip(結果) で dict<Tk, Tv> を生成
       └─ 値とキーを元に戻す
3. 結果の dict を返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[flip で値とキーを入れ替え]
    B --> C[dict<Tv, Tk> 生成]
    C --> D[再度 flip で値とキーを入れ替え]
    D --> E[dict<Tk, Tv> 生成]
    E --> F[結果を返却]
    F --> G[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-89-01 | 後のキー優先 | 重複する値がある場合、後に出現したキーが保持される | 重複値が存在する場合 |
| BR-89-02 | 値の型制約 | 値の型 Tv は arraykey（int または string）でなければならない | 常時 |
| BR-89-03 | 一意性保証 | 結果の dict では全ての値が一意である | 常時 |
| BR-89-04 | 順序変更 | 結果の順序は元の順序と異なる可能性がある | 常時 |

### 計算ロジック

二重フリップによる重複除去:
1. 最初の flip: dict<Tk, Tv> -> dict<Tv, Tk>
   - 同じ値 v に対して複数のキーがある場合、後のキーで上書き
2. 二番目の flip: dict<Tv, Tk> -> dict<Tk, Tv>
   - 一意の値に対応するキーのみが残る

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

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

本関数はデータベース操作を行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 型エラー | Tv が arraykey でない場合 | Hack型システムによりコンパイル時に検出 |

### リトライ仕様

本関数は純粋関数であり、リトライの概念は適用されない。

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

本関数はステートレスな純粋関数であり、トランザクション管理は不要。

## パフォーマンス要件

- 時間計算量: O(n)
- 空間計算量: O(n)

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

- 純粋関数であり、副作用がないためセキュリティリスクは低い
- 入力データの検証は呼び出し元の責任

## 備考

- 値が arraykey でない場合は `Dict\unique_by()` を使用すること
- 二重フリップの実装により、非常にシンプルで効率的な実装になっている
- 結果の順序は元の順序と異なる可能性があるため、順序が重要な場合は注意

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | select.php | `src/dict/select.php` | unique 関数のシグネチャと型パラメータ |
| 1-2 | transform.php | `src/dict/transform.php` | flip 関数の実装（122-130行目） |

**読解のコツ**: `Tv as arraykey` の制約に注目。値が arraykey でなければならない理由は、flip でキーとして使用するため。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | select.php | `src/dict/select.php` | unique 関数の実装（218-222行目） |

**主要処理フロー**:
1. **218-220行目**: 関数シグネチャの定義 - Tv as arraykey の制約
2. **221行目**: flip(flip($traversable)) による二重フリップ

#### Step 3: 依存関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | transform.php | `src/dict/transform.php` | flip 関数の実装（122-130行目） |

**主要処理フロー**:
- **122-130行目**: flip は foreach で値をキーに、キーを値にした dict を生成
- **127行目**: `$result[$value] = $key` - 同じ値がある場合、後のキーで上書き

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

```
Dict\unique($traversable)
    |
    +-- Dict\flip($traversable)  [第一フリップ: dict<Tk, Tv> -> dict<Tv, Tk>]
    |       |
    |       +-- foreach で値とキーを入れ替え
    |       +-- 重複する値は後のキーで上書き
    |
    +-- Dict\flip(結果)  [第二フリップ: dict<Tv, Tk> -> dict<Tk, Tv>]
            |
            +-- foreach で値とキーを入れ替え
```

### データフロー図

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

$traversable ─────────> flip() ─────────> flip() ─────────> dict<Tk, Tv>
(KeyedTraversable)      |                 |                 (一意の値のみ)
                        v                 v
                   dict<Tv, Tk>      dict<Tk, Tv>
                   (重複値は後の     (一意のキーと値)
                    キーで上書き)

例:
  dict['a' => 1, 'b' => 2, 'c' => 2, 'd' => 1]
  -> flip -> dict[1 => 'd', 2 => 'c']  (後のキーが優先)
  -> flip -> dict['d' => 1, 'c' => 2]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| select.php | `src/dict/select.php` | ソース | unique 関数の実装 |
| transform.php | `src/dict/transform.php` | ソース | flip 関数の実装 |
| DictSelectTest.php | `tests/dict/DictSelectTest.php` | テスト | unique のユニットテスト（439-464行目） |
