[Tips] Apexで二つのオブジェクトのリストをマージする方法あれこれ

2023.04.19

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

Apexにて、二つのオブジェクトのリストを特定のkeyを使ってマージしたいケースがあったので方法を調べました。

List<A__c> aObjects = [SELECT Key__c, X__c FROM A__c];
// 
// 例えば次のリストが得られるとする
// [
//  {
//    Key__c: 'hhh',
//    X__c: 'Dog_1'
//  },
//  {
//    Key__c: 'jjj',
//    X__c: 'Dog_2'
//  }
// ]

List<B__c> bObjects = [SELECT Key__c, Y__c FROM B__c];
//
// 例えば次のリストが得られるとする
// [
//  {
//    Key__c: 'hhh',
//    Y__c: 'Cat_1'
//  },
//  {
//    Key__c: 'iii',
//    X__c: 'Cat_2'
//  }
// ]

// この時に、次のマージしたリストを得たい
List<C__c> cObjects = mergeLists(aObjects, bObjects);
//
// [
//  {
//    Key__c: 'hhh',
//    X__c: 'Dog_1',
//    Y__c: 'Cat_1'
//  },
//  {
//    Key__c: 'iii',
//    X__c: null,
//    Y__c: 'Cat_2'
//  },
//  {
//    Key__c: 'jjj',
//    X__c: 'Dog_2',
//    Y__c: null
//  }
// ]

KeyにIdを使う場合

マージに使うKeyにId項目を使う場合はMapを活用して次のように実現できます。

Map<Id, A__c> aObjectsMap = new Map<Id, A__c>([SELECT Id, X__c FROM A__c]);
List<B__c> bObjects = [SELECT Id, Y__c FROM B__c];

List<C__c> cObjects = new List<C__c>();
for ( B__c bObject : bObjects ) {
    // MapからIdが等しいA__cのレコードを得る
    A__c aObject = (A__c)aObjectsMap.get(bObject.Id);

    // C__cオブジェクトに設定してリストに詰める
    C__c cObject = new C__c();
    cObject.Key__c = aObject.Id;
    cObject.X__c = aObject.X__c;
    cObject.Y__c = bObject.Y__c;
    cObjects.add(cObject);
}

ちなみに、最初のMapを作る処理は次のようにもできます。

List<A__c> aObjects = [SELECT X__c FROM A__c];
Map<Id, A__c> aObjectsMap = new Map<Id, A__c>(aObjects);

SOQLでIdをとっていなくても、ListからIdをKeyとするMapに変換することで自動でIdをセットしてくれます。

KeyにId以外を使う場合

マージに使うKeyにId項目以外を使う場合は最初のMapを作るまでに一工夫必要です。

List<A__c> aObjects = [SELECT Key__c, X__c FROM A__c];
Map<String, A__c> aObjectsMap = new Map<String, A__c>();
for ( A__c aObject : aObjects ) {
    aObjectsMap.put(aObject.Key__c, aObject);
}

// あとはこのMapを使ってマージ処理を行う
List<B__c> bObjects = [SELECT Key__c, Y__c FROM B__c];

List<C__c> cObjects = new List<C__c>();
for ( B__c bObject : bObjects ) {
    // MapからKey__cが等しいA__cのレコードを得る
    A__c aObject = (A__c)aObjectsMap.get(bObject.Key__c);

    // C__cオブジェクトに設定してリストに詰める
    C__c cObject = new C__c();
    cObject.Key__c = aObject.Key__c;
    cObject.X__c = aObject.X__c;
    cObject.Y__c = bObject.Y__c;
    cObjects.add(cObject);
}

まとめ

Map型のKeyにマージに使いたいKey値を設定することで、二つのリストをマージする方法を示しました。
考え方はシンプルですので、意外と簡単だと感じられたのではないでしょうか。

See Also

Is it possible to run a SOQL Query and get a MAP returned?