リスト型のソート機能使ってみた

最近はMuleメインだったので久々にSalesforce記事をアップします。Winter24で追加されたComparatorクラスを使ったリスト型のソートになります。

スポンサーリンク

従来のソート機能の問題点

従来の機能では、取得したリストをソートする場合は以下のいずれかの方法で実装する必要がありました。

  • SOQLのOrder By句
  • Listのsort()メソッド

まず、SOQLのOrder Byについては、そもそもオブジェクトに対してしか使用できないため、Dtoクラスのリストなどはfor文などで解いて1個ずつ見比べる必要がありました。また、並び順についても数値型であれば数の大小でソートはしてくれるものの、選択リストなどの文字列(コード値)は単なるアルファベット順となってしまうため、こちらが意図した通りの並び替えができませんでした。Listのsort()メソッドについても同様で、こちらでロジックが組み立てられるわけではないため基本数字の大小かアルファベット順くらいのソートで妥協するしかありませんでした。

今までの従来の問題点を解消したのがComparatorインタフェースクラスを使用したソート機能になります(リリースノート)。

Comparatorクラスを使ったソート

今回新しく追加されたComparatorインタフェースを使用した並べ替えです。今まで数字の大小やアルファベット順でしかソートできなかったものが、独自にソートのロジックを組むことができ、かつオブジェクトやクラスなどにも対応した並べ替えができるような仕組みになっています。

では実際作成してみましょう。まずは、比較のロジックとなるComparatorクラスを作成します。オブジェクト同士を比較するComparatorクラスの書き方は以下のように記載します。

public class クラス名 implements Comparator<オブジェクト名> {
    public Integer compare(sObject s1, sObject s2) {
        Integer returnValue = 0;
        // 比較ロジック
        // s1 = s2の場合は戻り値を0にする
        // s1 < s2の場合は戻り値を-1にする
        // s1 > s2の場合は戻り値を1にする        
        return returnValue;
    }
}

オブジェクト名のところはクラス名やプリミティブ型でもOKです。
実際に実装すべきはcompareメソッドで、引数が2つ与えられ、このメソッドで大小関係を定義します。

上記の書き方をベースにLeadオブジェクトのRating(評価)に対して比較を行う場合は以下のように記載します。Ratingの値については null < Cold < Warm < Hotとなるように比較のロジックを実装しています。

public class LeadComparator implements Comparator<Lead> {
    public Integer compare(Lead l1, Lead l2) {
        // 比較結果
        //  -1:左側の値が小さい
        //  0:両方の値が同じ
        //  1:右側の値が小さい
        Integer returnValue = 0;
        
        // リードのRatingを数値化
        Integer l1rating = convertRating(l1);
        Integer l2rating = convertRating(l2);
        
        // 比較
        if(l1rating < l2rating){
            returnValue = -1;
        } else if (l1rating > l2rating) {
            returnValue = 1;
        }
        return returnValue;
    }
    
    private Integer convertRating(Lead l){
        // リードのRatingを数値化
        // -1:オブジェクトがnull
        // 0:Ratingがnull
        // 1:RatingがCold
        // 2:RatingがWarm
        // 3:RatingがHot
        Integer ratingNum = -1;
        if(l != null){
            if (l.Rating == null){
                ratingNum = 0;
            } else if (l.Rating == 'Cold') {
                ratingNum = 1;
            } else if (l.Rating == 'Warm') {
                ratingNum = 2;
            } else if (l.Rating == 'Hot') {
                ratingNum = 3;
            }
        }
        return ratingNum;
    }
}
List<Lead> leadList = new List<Lead>{
   new Lead(LastName='hoge', Company='hoge', Rating = 'Hot'),
   new Lead(LastName='hoge', Company='hoge', Rating = 'Cold'),
   new Lead(LastName='hoge', Company='hoge', Rating = null),
   new Lead(LastName='hoge', Company='hoge', Rating = 'Warm')
};
    
System.debug('◆ソート前');
System.debug(leadList);
// ソート
leadList.sort(new LeadComparator());
System.debug('◆ソート後');
System.debug(leadList);

ソート結果はこのようになります(分かりやすいようにRating部分を色分け)。

◆ソート前
(Lead:{LastName=hoge, Company=hoge, Rating=Hot}, Lead:{LastName=hoge, Company=hoge, Rating=Cold}, Lead:{LastName=hoge, Company=hoge, Rating=null}, Lead:{LastName=hoge, Company=hoge, Rating=Warm})
◆ソート後
(Lead:{LastName=hoge, Company=hoge, Rating=null}, Lead:{LastName=hoge, Company=hoge, Rating=Cold}, Lead:{LastName=hoge, Company=hoge, Rating=Warm}, Lead:{LastName=hoge, Company=hoge, Rating=Hot})

ソート結果から自作したComparatorクラスの比較ロジックが機能していることが分かります。

これにより、より複雑なクラスでも1つ比較ロジックを作ることによってソートができることになりました。Order Byで手が届かなかったところなどで活用してみてください。

コメント