0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Apex】List / Set / Map まとめ

Posted at

🔽 【Apex】List / Set / Map の特徴・違い・使い方まとめ

Apex でよく使うコレクション型 List / Set / Map の特徴・違い・使い方をまとめました。

✅ まず押さえるべきポイント💡

  • List : インデックスで識別される要素の順序付けされたコレクション
  • Set : 重複を含まない要素の順序付けされていないコレクション
  • Map : 単一の値に一意のキーを対応付ける、キー - 値のペアのコレクション

image.png

1. Listとは

Apex において 最も基本的に使うコレクション型List です。
順序付きで、重複を許容する点が最大の特徴です。

  • 順序を保持(インデックス 0 から順番にアクセス可能)
  • 同じ値を何度でも格納できる(重複あり)
  • SOQL のクエリ結果は基本的に List<SObject> で返される

🔹 Listの使い方

// 初期化
List<String> fruits = new List<String>();

// 挿入
fruits.add('Apple');
fruits.add('Banana');
fruits.add('Apple'); // 重複OK

// 取得
System.debug(fruits); // => (Apple, Banana, Apple)
System.debug(fruits[0]);       // => "Apple"
System.debug(fruits.size());   // => 3

// 値を更新(2番目を Mango に変更)
fruits[1] = 'Mango';

// 要素を削除(0番目を削除)
fruits.remove(0);

System.debug(fruits); // => (Mango, Apple)

👉 List の代表的なメソッド一覧の詳細はこちらから
https://developer.salesforce.com/docs/atlas.ja-jp.apexcode.meta/apexcode/apex_methods_system_list.htm#apex_System_List_methods

🔹 Listの利用例

  • 順序を保持する必要があるデータ(例: タスクの処理順、履歴の記録)
  • 重複を許容するデータ(例: 注文リスト、履歴ログ)
  • SOQL 結果の格納(例: List contacts = [SELECT Id, Name FROM Contact];)

2. Setとは

Apex において ユニークな値を保持したいときに使うコレクション型Set です。
「順序は保持せず、重複を許さない」点が最大の特徴です。

  • 順序を保持しない(インデックスアクセス不可)
  • 重複した値は自動的に排除される
  • 値の存在確認が高速

🎯 ポイント
「同じ値を 2 回入れても 1 つにまとまる」というのが最大のポイント!

Setの使い方

// 初期化
Set<String> fruits = new Set<String>();

// 挿入
fruits.add('Apple');
fruits.add('Banana');
fruits.add('Apple'); // 重複は無視される

System.debug(fruits); // => {Apple, Banana}

// 存在確認
System.debug(fruits.contains('Apple')); // => true
System.debug(fruits.contains('Mango')); // => false

// 値の削除
fruits.remove('Apple');
System.debug(fruits); // => {Banana}

⚠️ Set はインデックスを持たないため、fruits[0] のようなアクセスはできません。
重複排除の目的で、SOQL の結果 List を Set に変換可能

🔹 SOQL との組み合わせ

// 重複ありの List
List<Id> contactIds = new List<Id>{'000XXX1', '000XXX2', '000XXX1'};

// Set に変換して重複排除
Set<Id> uniqueContactIds = new Set<Id>(contactIds);

System.debug(uniqueContactIds); // => {'003XXX1', '003XXX2'}

🔹 Set の便利メソッド

Set<Integer> numbers = new Set<Integer>{1, 2, 3};
Set<Integer> others  = new Set<Integer>{3, 4, 5};

// 結合(和集合)
numbers.addAll(others); 
// => {1, 2, 3, 4, 5}

// 共通部分(積集合)
Set<Integer> common = numbers.clone();
common.retainAll(others); 
// => {3, 4, 5}

// 差集合
Set<Integer> diff = numbers.clone();
diff.removeAll(others); 
// => {1, 2}

👉 Set の代表的なメソッド一覧の詳細はこちらから
https://developer.salesforce.com/docs/atlas.ja-jp.apexcode.meta/apexcode/apex_methods_system_set.htm#apex_System_Set_methods

🔹 Setの利用例

1. メールアドレスの重複排除

List<String> inputEmails = new List<String>{
    'test@example.com', 
    'user@example.com', 
    'test@example.com' // 重複あり
};

// Set に変換して重複排除
Set<String> uniqueEmails = new Set<String>(inputEmails);

System.debug(uniqueEmails); 
// => {test@example.com, user@example.com}

🎯 ポイント
「一斉メール送信処理」で、同じメールアドレスに複数回送らないように使用できる。

2. ID の集合管理(SOQL の IN 条件で利用)

// Contact を検索
List<Contact> contacts = [SELECT Id, AccountId FROM Contact WHERE Email != null];

// AccountId を Set に変換(重複自動排除)
Set<Id> accIds = new Set<Id>();
for(Contact c : contacts){
    accIds.add(c.AccountId);
}

// 重複しない Account を一括取得
List<Account> accounts = [SELECT Id, Name FROM Account WHERE Id IN :accIds];

List で取得したデータから ID を取り出し、Set にまとめて SOQL の IN 条件 に使用。
👉 これにより「関連する Account を重複なく取得する」ことができます。

3. 存在チェックの高速化

// すでに登録済みの Email 一覧
Set<String> registeredEmails = new Set<String>{
    'a@example.com', 'b@example.com'
};

// 新しいユーザを登録する処理
String newEmail = 'a@example.com';

if(registeredEmails.contains(newEmail)){
    System.debug('すでに登録済みです');
} else {
    System.debug('新規登録可能です');
}

🎯 ポイント
大量のデータを処理するとき、Set は 「この値が含まれているか?」を一瞬で判定
👉 登録済みかどうか判定してバリデーションや二重登録を防止

3. Mapとは

Apex において Key と Value を対応付けて管理できるコレクション型Map です。
「Key は一意で重複不可、Value は重複可」というのが最大の特徴です。

// 基本構文
Map<KeyType, ValueType> 変数名 = new Map<KeyType, ValueType>();
//	KeyType : キーの型(例: Id, String, Integer など)
//	ValueType : 値の型(例: String, Account, List<Contact> など)

Mapの使い方

// 初期化
Map<String, String> countryCapital = new Map<String, String>();

// 挿入
countryCapital.put('Japan', 'Tokyo');
countryCapital.put('France', 'Paris');
countryCapital.put('Japan', 'Kyoto'); // 同じキーを上書き

// Key を指定して取得
System.debug(countryCapital.get('Japan'));         // => "Kyoto"
System.debug(countryCapital.containsKey('France')); // => true

🔎 List vs Map 検索処理の比較

✅ List で検索の場合

  • 要素を順番に調べていく必要がある
  • データが増えるほどループが長くなる(効率が悪い)
// Contactリストを取得
List<Contact> contacts = [SELECT Id, Name FROM Contact LIMIT 5];

// 探したいId
Id targetId = contacts[0].Id; 
Contact foundContact;

// 検索処理(ループが必要)
for(Contact c : contacts){
    if(c.Id == targetId){
        foundContact = c;
        break; // 見つかったら終了
    }
}

System.debug('List検索結果: ' + foundContact.Name);

✅Map で検索の場合

  • Id を Key にして SObject を一発検索
// ContactをMap化(IdをKey)
Map<Id, Contact> contactMap = new Map<Id, Contact>(
    [SELECT Id, Name FROM Contact LIMIT 5]
);

// 探したいId(ここでは仮のIdを直接指定)
Id targetId = '003XXXXXXXXXXXX'; 

// 検索処理(getで一発)
Contact foundContact = contactMap.get(targetId);

System.debug('Map検索結果: ' + foundContact.Name);

🔹 Mapの利用例

1. SOQL 結果を ID 紐付けで高速検索

// Contact のリスト取得
List<Contact> cons = [SELECT Id, AccountId, LastName FROM Contact];

// 関連する Account を一括取得 → Map化
Map<Id, Account> accMap = new Map<Id, Account>(
    [SELECT Id, Name FROM Account 
     WHERE Id IN :new Map<Id, Contact>(cons).values().AccountId]
);

// Contact に関連する Account 名を参照
for(Contact c : cons){
    Account a = accMap.get(c.AccountId); // Idから一発検索
    System.debug(c.LastName + ' さんの会社は ' + a.Name);
}

📌 解説

  • new Map(cons) で Contact リストをそのまま Map 化できる
  • その values() を使って AccountId をまとめて抽出し、関連 Account を一括取得
  • accMap.get(c.AccountId) で ループ内 SOQL 不要 & 高速検索が可能

🎯 ポイント
SOQL で取得した SObject を Map に変換すると、ID をキーにして直接参照できるようになる

2. 親子データのひも付け処理

// ① Contact を取得(AccountId付き)
List<Contact> cons = [SELECT Id, AccountId FROM Contact LIMIT 50];

// ② Account を Map 化
Set<Id> accIds = new Set<Id>();
for(Contact c : cons){
    if(c.AccountId != null){
        accIds.add(c.AccountId);
    }
}
Map<Id, Account> accMap = new Map<Id, Account>(
    [SELECT Id, Name FROM Account WHERE Id IN :accIds]
);

// ③ Case を作成する際に Account 名を参照
List<Case> newCases = new List<Case>();
for(Contact c : cons){
    if(accMap.containsKey(c.AccountId)){
        newCases.add(new Case(
            ContactId = c.Id,
            Subject   = '問い合わせ: ' + accMap.get(c.AccountId).Name
        ));
    }
}

insert newCases;

📌 解説
• Contact から AccountId を集めておき、一括 SOQL で Account を取得 → Map 化
• ループ内で accMap.get(c.AccountId) により 関連する Account 名をすぐ参照
• これにより N+1 SOQL 問題を回避しつつ、親子データのひも付けが簡単になる

まとめポイント

特徴

  • List : 順序重視・重複OK
  • Set : ユニーク性重視・順序不要・存在チェックが高速
  • Map : キーで値を管理・キーはユニーク・SOQL結果の効率的アクセスに便利

使い分け

  • List : タスク処理順や履歴記録、重複データを扱うとき
  • Set : メールアドレスの重複排除、ID集合管理、存在チェック
  • Map : SObjectをIDで参照したい場合、関連情報の高速取得

📚 参考資料

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?