BETA

条件の数が可変なArray.filter()をやりたかったポエム

投稿日:2020-06-18
最終更新:2020-06-18

動機

ダッシュボードみたいなの作ってて、フィルタリング条件が増えたり減ったりして実装がめんど臭い事が多々あるのであらがってみたかった。MongoのQueryみたいなの妄想したけど、andとかorの条件ネストは諦めた。

そんなに続いてるわけでもないけどコレの続き。

やりたかった事

var data = [  
    {b: 500, g:{value: 30}},  
    {b: 200},  
    {b: 100},  
    {b: 300},  
    {string: "aiue", g:{value: 200}},  
    {string: "aiueo", g:{value: 300}},  
]  

これに

var conditionParams = [  
    {type: "match", "key": ["string"], "value": "ueo"},  
    {type: "lt", "key": ["g", "value"], "value": 400},  
]  

これを

oreoreFilter(data, conditionParams, genCondition, true);  

こうすると

// -> [ {string: "aiueo", g:{value: 300}} ]  

ANDでフィルタリングされてこうなる。

ゆるふわ実装

// ネストされたオブジェクトをキーで取り出すやつ  
function search(data,keys){  
    console.log(data, keys);  
    return keys.reduce((current, key) => {  
        try{  
            return current[key]  
        } catch(e) {  
            return undefined  
        }  
    }, data)  
}  

// 検索条件を組み立てるやつ  
// あとで挙動を変更したり追加できるようにミドルウェアみを持たせとく  
function genCondition(condition){  
    try{  
        switch(condition.type){  
            case "eq": return (value)=>{ return search(value, condition.key) === condition.value;  }  
            case "gt": return (value)=>{ return search(value, condition.key) > condition.value; }  
            case "lt": return (value)=>{ return search(value, condition.key) < condition.value; }  
            case "ge": return (value)=>{ return search(value, condition.key) <= condition.value; }  
            case "le": return (value)=>{ return search(value, condition.key) <= condition.value;  }  
            case "match": return (value)=>{ return new RegExp(`.*${condition.value}.*`).test(search(value, condition.key)); }  
            default: return ()=> false;  
        }  
    } catch (e){  
        return false;  
    }  
}  

// フィルタリング処理  
// 対象の配列に対して実際にフィルタリングする関数  
function oreoreFilter(data, conditionParams, genCondition, flg){  
    const conditions = conditionParams.map(genCondition)  

    return data.filter((value)=>{  
        return conditions.reduce(  
            (sum, condition)=>{         
                // 申し訳程度のAND/OR要素  
                if (flg){  
                    return sum && condition(value)  
                }   
                return sum || condition(value)  
            }  
        ,flg)  
    })  
}  

テスト

var data = [  
    {b: 500, g:{value: 30}},  
    {b: 200, g:{value: 500}},  
    {b: 200, g:{value: 300}},  
    {b: 100},  
    {b: 300},  
    {string: "aiue", g:{value: 200}},  
    {string: "aiueo", g:{value: 500}},  
]  


var conditionParams = [  
    {type: "gt", "key": ["b"], "value": 100},   
    {type: "lt", "key": ["b"], "value": 700},  
    {type: "lt", "key": ["g", "value"], "value": 400},  
]  

// AND検索  
oreoreFilter(data, conditionParams, genCondition, true);  
// ->  [ {b: 500, g:{value: 30}},    {b: 200, g:{value: 300}} ]  

// OR検索  
oreoreFilter(data, conditionParams, genCondition, false);  
// ->  [  
//         {b: 500, g:{value: 30}},  
//         {b: 200, g:{value: 500}},  
//         {b: 200, g:{value: 300}},  
//         {b: 100},  
//         {b: 300},  
//         {string: "aiue", g:{value: 200}},  
//      ]  

まとめ

とりあえず動いてる気がする。

技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
駆け出しエンジニアからエキスパートまで全ての方々のアウトプットを歓迎しております!
or 外部アカウントで 登録 / ログイン する
クランチについてもっと詳しく

この記事が掲載されているブログ

okd.shのTechのフリしたポエム

よく一緒に読まれる記事

0件のコメント

ブログ開設 or ログイン してコメントを送ってみよう