RPG

157. 任意の柔軟な SORT を実現するには ?

ここでは高度な SORT の事例を紹介する。
SORTA については既に多くの読者もご存知であると思うが社内事情によって
文字列の並び順とはいかない、独自の順序で並べることができるだろうか ?
例えば品種コード順に単純に分類するのではなく、品種の中でもある重要な
品種については先頭に表示したいような場合である。
このような独自の分類を行いたい場合には C言語で用意されている関数 : qsort
効果的である。
qsort 関数を活用することができれば、どのような順序にでも思いのままに
SORT することができる。

-------------------------------------------------------------------------------
0001.00 H DFTNAME(TESTSORTC) DATEDIT(*YMD/)                                    
0002.00 H DFTACTGRP(*NO) BNDDIR('QC2LE')                                       
0003.00 F********** SORTのサンプル ****************************************
0004.00 F*    QSORT による SORT                                                
0005.00 F*****************************************************************     
0006.00 D COMPARE         PR            10I 0                                  
0007.00 D  FLDA                           *   VALUE                            
0008.00 D  FLDB                           *   VALUE                            
0009.00                                                                        
0010.00 D QSORT           PR                  EXTPROC('qsort')                 
0011.00 D  ARRAY                          *   VALUE                            
0012.00 D  ITEMSU                       10I 0 VALUE                            
0013.00 D  SIZE                         10I 0 VALUE                            
0014.00 D  COMPARE                        *   VALUE PROCPTR                    
0015.00                                                                        
0016.00 D CDR             S              4    DIM(3) CTDATA PERRCD(1)          
0017.00 D NMR             S             14    DIM(3) CTDATA PERRCD(1)          
0018.00 D STR             S             18    DIM(3)                           
0019.00                                                                        
0020.00 C                   MOVEL     CDR           STR                        
0021.00 C                   MOVE      NMR           STR                        
0022.00 C* SORT 前のデータの表示                                               
0023.00 C     1             DO        3             N                 4 0      
0024.00 C     STR(N)        DSPLY                                            
0025.00 C                   END                                              
0026.00 C     '*END OF DATA'DSPLY                   ANS               1      
0027.00 C*                                                                   
0028.00 C* QSORT によって昇順に並べる                                        
0029.00 C                   CALLP     QSORT(%ADDR(STR):3:18:%PADDR(COMPARE)) 
0030.00 C*                                                                   
0031.00 C     1             DO        3             N                 4 0    
0032.00 C     STR(N)        DSPLY                                            
0033.00 C                   END                                              
0034.00 C     '*END OF SORT'DSPLY                   ANS               1      
0035.00 C                   SETON                                        LR  
0036.00 *********************************************************            
0037.00 P COMPARE         B                                                  
0038.00 *********************************************************            
0039.00 D                 PI            10I 0                                
0040.00 D  FLDAP                          *   VALUE                          
0041.00 D  FLDBP                          *   VALUE                          
0042.00                                                                      
0043.00 D FLDA            S             18A   BASED(FLDAP)                   
0044.00 D FLDB            S             18A   BASED(FLDBP)                   
0045.00                                                                      
0046.00 C                   SELECT                                           
0047.00 C                   WHEN      FLDA > FLDB                            
0048.00 C                   RETURN                  1 
0049.00 C                   WHEN      FLDA < FLDB     
0050.00 C                   RETURN                 -1 
0051.00 C                   OTHER                     
0052.00 C                   RETURN                  0 
0053.00 C                   ENDSL                     
0054.00 P                 E                           
0055.00 ** CDR         
0056.00 0002           
0057.00 0001           
0058.00 0003           
0059.00 ** NMR         
0060.00  ビデオデッキ  
0061.00  カラーTV    
0062.00  コンボ        
-------------------------------------------------------------------------------
【 コンパイル 】
      CRTBNDRPG MYLIB/TESTSORTC SRCFILE(MYSRCLIB/QRPGLESRC) AUT(*ALL)
【 解説 】

まず H-仕様書では

  H DFTACTGRP(*NO) BNDDIR('QC2LE')

によって QC2LE という C関数のバインド・ディリクトリーを定義することによって
C関数を取り込むようにする。
qsort 関数は

  qsort(SORTする配列のポインター : 配列の項目数 : 項目の長さ : 比較関数のポインター) 

として関数の型が定義されていると解釈してよいだろう。
実際は

 ( void qsort(void *base, size_t num, size_t, width, int(*compare)(const void *elem1,const void *elem2));   )

として定義されているが RPG開発者にとっては上記の解釈で十分である。
ここで qsort が汎用的であるのは SORT のために比較を判断する関数 compare
ユーザー定義であることである。
そこで比較関数を

   0006.00 D COMPARE         PR            10I 0                                       
   0007.00 D  FLDA                           *   VALUE                                 
   0008.00 D  FLDB                           *   VALUE

としてユーザー定義する。バラメータは2つの項目のポインターが渡されるので
1 を戻り値として戻せば、その比較は正常であることを qsort に伝えて、
-1 を戻り値として戻せば、その比較は入れ替えが必要であることを qsort に伝えることができる。
このようにして qsort はユーザーが定義した比較関数の指示に従って SORT を行うのである。
従って比較関数 COMPARE の中でユーザーはどのような分類順序であっても自由に定義することが
できるのである。
これよって COMPARE を工夫しさえすれば自由度の高いユーザー定義による SORT をいくらでも
実現することができる。
次はこの SORT による実行の様子を示している。