Home > Windows にまつわる e.t.c.

PowerShell で N:N キー マッチングする


古典的な N:N キー マッチングを PowerShell で書く機会があったので、汎用化してみました。
(もう少しすっきり書けそうですが、いろいろいじるとテストが面倒なのでほぼそのまま w)

 

機能

・2つオブジェクト(Master/Tran)の任意プロパティをマッチング キーにしてキー マッチングします。
・Master だけのオブジェクト、Tran だけのオブジェクト、マッチしたオブジェクトを返します。
・同一キーが複数存在している場合は、最初に処理をしたオブジェクトのみ対象にします(以降のキー重複オブジェクトは読み飛ばし)

 

使い方

以下のマッチング キー ハンドリング部分を修正し、コードを組み込んでください。

【MasterKeyProperty】
【TranKeyProperty】

 

キーが複数ある場合は、 sort は複数キー指定ができますの。キー セットはよしなに修正してください。

 

コード

# マッチング状態定数
$LC_Mode_Matchi = 0
$LC_Mode_MasterOnly = 1
$LC_Mode_TranOnly = 2
$LC_Mode_Oter = 9

#######################################################
# マスター Key セット
#######################################################
function SetMasterKey($MasterObjects){
    return $MasterObjects.【MasterKeyProperty】
}

#######################################################
# トランキー Key セット
#######################################################
function SetTranKey($TranObjects){
    return $TranObjects.【TranKeyProperty】
}

#######################################################
# マッチング 状態判定
#######################################################
function GetMatchingStatus( $MasterKey, $Master_EOD, $TranKey, $Tran_EOD ){
    $ReturnMode = $LC_Mode_Oter

    # マスター終了
    if( $Master_EOD -eq $true ){
        $ReturnMode = $LC_Mode_TranOnly
    }

    # トラン終了
    elseif( $Tran_EOD -eq $true ){
        $ReturnMode = $LC_Mode_MasterOnly
    }

    # キーが等しい
    elseif( $MasterKey -eq $TranKey ){
        $ReturnMode = $LC_Mode_Matchi
    }

    # マスターが小さい
    elseif( $MasterKey -lt $TranKey ){
        $ReturnMode = $LC_Mode_MasterOnly
    }

    # トランが小さい
    elseif( $TranKey -lt $MasterKey ){
        $ReturnMode = $LC_Mode_TranOnly
    }

    return $ReturnMode
}

#######################################################
# マッチング処理
#######################################################
function Matching([array]$MasterObjects, [array]$TranObjects){

    ### Master前処理
    # Master 終わったフラグ
    $Master_EOD = $false
    # Sort
    [array]$MasterData = $MasterObjects | Sort-Object 【MasterKeyProperty】
    # Max 件数
    $Master_Max = $MasterData.Count
    # Key 初期セットset
    $Master_Index = 0
    if( $MasterData.Count -ne 0 ){
        $MasterKey = SetMasterKey $MasterData[$Master_Index]
    }
    else{
        $Master_EOD = $true
    }

    ### Tran 前処理
    # Tran 終わったフラグ
    $Tran_EOD = $false
    # Sort
    [array]$TranData = $TranObjects | Sort-Object 【TranKeyProperty】
    # Max 件数
    $Tran_Max = $TranData.Count
    # Key 初期セットset
    $Tran_Index = 0
    if( $TranData.Count -ne 0 ){
        $TranKey = SetTranKey $TranData[$Tran_Index]
    }
    else{
        $Tran_EOD = $true
    }

    # Master Only Data
    $MasterOnlyData = @()

    # Tran Only Data
    $TranOnlyData = @()

    # MatchData
    $MatchData = @()

    # 件数カウンター
    $MatchCount = 0
    $MasterOnlyCount = 0
    $TranOnlyCount = 0


    # マッチング
    while( -not (($Master_EOD -eq $true) -and ($Tran_EOD -eq $true)) ){

        # マッチング 状態取得
        $MatchingStatus = GetMatchingStatus $MasterKey $Master_EOD $TranKey $Tran_EOD

        # Master Only
        if( $MatchingStatus -eq $LC_Mode_MasterOnly ){

            # Master データ収集
            $AddData = $MasterData[$Master_Index]
            $MasterOnlyData += $AddData

            # Master Key Set
            $NowKey = $MasterKey

            # キーが割れるまで読み飛ばす
            do{
                # 件数カウント
                $MasterOnlyCount++

                $Master_Index++
                if( $Master_Index -ge $Master_Max ){
                    $Master_EOD = $true
                    $NewKey = $null
                }
                else{
                    $MasterKey = SetMasterKey $MasterData[$Master_Index]
                    $NewKey = $MasterKey
                }
            }while( $NowKey -eq $NewKey )

        }
        # Tran Only
        elseif( $MatchingStatus -eq $LC_Mode_TranOnly ){

            # Tran データ収集
            $AddData = $TranData[$Tran_Index]
            $TranOnlyData += $AddData

            # Tran Key Set
            $NowKey = $TranKey

            # キーが割れるまで読み飛ばす
            do{
                # 件数カウント
                $TranOnlyCount++

                $Tran_Index++
                if( $Tran_Index -ge $Tran_Max ){
                    $Tran_EOD = $true
                    $NewKey = $null
                }
                else{
                    $TranKey = SetTranKey $TranData[$Tran_Index]
                    $NewKey = $TranKey
                }
            }while( $NowKey -eq $NewKey )
        }

        # マッチ
        else{

            # Match データ収集
            # (Master をセット。必要に応じて Tran セットに書き換える)
            $AddData = $MasterData[$Master_Index]
            $MatchData += $AddData

            # Master Key Set
            $NowKey = $MasterKey

            # キーが割れるまで読み飛ばす
            do{
                # 件数カウント
                $MatchCount++

                $Master_Index++
                if( $Master_Index -ge $Master_Max ){
                    $Master_EOD = $true
                    $NewKey = $null
                }
                else{
                    $MasterKey = SetMasterKey $MasterData[$Master_Index]
                    $NewKey = $MasterKey
                }
            }while( $NowKey -eq $NewKey )


            # Tran Key Set
            $NowKey = $TranKey
            do{ # キーが割れるまで読み飛ばす
                $Tran_Index++
                if( $Tran_Index -ge $Tran_Max ){
                    $Tran_EOD = $true
                    $NewKey = $null
                }
                else{
                    $TranKey = SetTranKey $TranData[$Tran_Index]
                    $NewKey = $TranKey
                }
            }while( $NowKey -eq $NewKey )
        }
    }


    # 戻り値セット
    $ReturnData = New-Object PSObject | Select-Object`
            MasterOnlyData, # マスターオンリー
            MatchData,      # マッチ
            TranOnlyData    # トランオンリー
            
    $ReturnData.MasterOnlyData = $MasterOnlyData
    $ReturnData.MatchData      = $MatchData
    $ReturnData.TranOnlyData   = $TranOnlyData

    return $ReturnData
}

 

実装例

MatchingTest.ps1

### ここにコードコピペ

# マスタセット
$MasterData = Import-Csv "C:\temp\MatchTest\Master.csv"

# トランセット
$TranData = Import-Csv "C:\temp\MatchTest\Tran.csv"

# マッチング
$RetData = Matching $MasterData $TranData

# マッチング結果データ取り出し
$MasterOnlyData = $RetData.MasterOnlyData
$TranOnlyData = $RetData.TranOnlyData
$MatchData = $RetData.MatchData

# マッチング結果表示
echo "MasterOnly : "
$MasterOnlyData | ft *
echo ""
echo "TranOnly   : "
$TranOnlyData | ft *
echo ""
echo "Match      : "
$MatchData | ft *

 

参考情報

PowerShell の Sort-Object Tips
http://www.vwnet.jp/windows/PowerShell/2017032901/Sort-Object_Tips.htm

 

 

back.gif (1980 バイト)

home.gif (1907 バイト)

Copyright © MURA All rights reserved.