配列系の処理を関数型で行いたいときにJavaだとラムダ式、javaScriptだとunderscore.jsがあります。
PHPではできないものか・・といろいろと探していたところunderbar.phpというライブラリが使えるようですね。
underbar.phpとは
公式は http://emonkak.github.io/underbar.php/
undersocre.jsに影響をうけたライブラリのようで、使い方も非常に似ています。
インストール
ライブラリを使いたいディレクトリにcomposer.jsonを作り、下記を書いてcomposer updateを行います。
1 2 3 4 5 |
{ "require": { "emonkak/underbar.php": "dev-master" } } |
vendor/autoload.phpというファイルがありますので、これを読み込めばunderbar.phpが使えます。
配列系の処理といっても一番使う頻度が高いのは多次元配列の抽出、集計、変換だと思いますので、これらの処理を中心に書いていきます。
集計
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
#冒頭でautoload.phpを読み込む require __DIR__ . './vendor/autoload.php'; use Underbar\ArrayImpl as _; //公式 $arr=[ ["name"=>" kazumi", "domain"=>"gmail.com", "age"=>"30","pref"=>"chiba"], ["name"=>"ichirou","domain"=>"yahoo.co.jp", "age"=>"18","pref"=>"tokyo"], ["name"=>" yuusuke","domain"=>"hotmail.com", "age"=>"25","pref"=>"chiba"], ["name"=>" satoshi","domain"=>"gmail.com", "age"=>"45","pref"=>"kanagawa"], ["name"=>"jirou ", "domain"=>"hotmail.com", "age"=>"9","pref"=>"tokyo"] ]; #特定条件で抽出(20才以上のレコードを取り出し) $arr2 = _::filter( $arr , function($ele) { return $ele["age"] >=20; }); var_dump( $arr2 ); //array(3) { // [0]=> // array(4) { // ["name"]=> // string(7) " kazumi" // ["domain"]=> // string(9) "gmail.com" // ["age"]=> // string(2) "30" // ["pref"]=> // string(5) "chiba" // } // [2]=> // array(4) { // ["name"]=> // string(8) " yuusuke" // ["domain"]=> // string(11) "hotmail.com" // ["age"]=> // string(2) "25" // ["pref"]=> // string(5) "chiba" // } // [3]=> // array(4) { // ["name"]=> // string(8) " satoshi" // ["domain"]=> // string(9) "gmail.com" // ["age"]=> // string(2) "45" // ["pref"]=> // string(8) "kanagawa" // } //} #where句のように使える $arr2 = _::where($arr, ['pref' => "chiba"]); var_dump( $arr2 ); //array(2) { // [0]=> // array(4) { // ["name"]=> // string(7) " kazumi" // ["domain"]=> // string(9) "gmail.com" // ["age"]=> // string(2) "30" // ["pref"]=> // string(5) "chiba" // } // [2]=> // array(4) { // ["name"]=> // string(8) " yuusuke" // ["domain"]=> // string(11) "hotmail.com" // ["age"]=> // string(2) "25" // ["pref"]=> // string(5) "chiba" // } //} #特定のプロパティだけを取り出す $arr2 = _::pluck($arr, 'domain'); var_dump( $arr2 ); //array(5) { // [0]=> // string(9) "gmail.com" // [1]=> // string(11) "yahoo.co.jp" // [2]=> // string(11) "hotmail.com" // [3]=> // string(9) "gmail.com" // [4]=> // string(11) "hotmail.com" //} |
集計
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
#集計 #県ごとにグルーピングgroupby これができると処理効率が全然違います。 $arr2 = _::groupBy( $arr, function($ele) { return $ele["pref"]; } ); var_dump( $arr2 ); //県ごとにグルーピング //array(3) { // ["chiba"]=> // array(2) { // [0]=> // array(4) { // ["name"]=> // string(7) " kazumi" // ["domain"]=> // string(9) "gmail.com" // ["age"]=> // string(2) "30" // ["pref"]=> // string(5) "chiba" // } // [1]=> // array(4) { // ["name"]=> // string(8) " yuusuke" // ["domain"]=> // string(11) "hotmail.com" // ["age"]=> // string(2) "25" // ["pref"]=> // string(5) "chiba" // } // } // ["tokyo"]=> // array(2) { // [0]=> // array(4) { // ["name"]=> // string(7) "ichirou" // ["domain"]=> // string(11) "yahoo.co.jp" // ["age"]=> // string(2) "18" // ["pref"]=> // string(5) "tokyo" // } // [1]=> // array(4) { // ["name"]=> // string(6) "jirou " // ["domain"]=> // string(11) "hotmail.com" // ["age"]=> // string(1) "9" // ["pref"]=> // string(5) "tokyo" // } // } // ["kanagawa"]=> // array(1) { // [0]=> // array(4) { // ["name"]=> // string(8) " satoshi" // ["domain"]=> // string(9) "gmail.com" // ["age"]=> // string(2) "45" // ["pref"]=> // string(8) "kanagawa" // } // } //} // //特定のプロパティで集計。重複がないパターンはこれが使える $arr3 = _::indexBy( $arr , 'pref'); var_dump( $arr3 ); //array(3) { // ["chiba"]=> // array(4) { // ["name"]=> // string(8) " yuusuke" // ["domain"]=> // string(11) "hotmail.com" // ["age"]=> // string(2) "25" // ["pref"]=> // string(5) "chiba" // } // ["tokyo"]=> // array(4) { // ["name"]=> // string(6) "jirou " // ["domain"]=> // string(11) "hotmail.com" // ["age"]=> // string(1) "9" // ["pref"]=> // string(5) "tokyo" // } // ["kanagawa"]=> // array(4) { // ["name"]=> // string(8) " satoshi" // ["domain"]=> // string(9) "gmail.com" // ["age"]=> // string(2) "45" // ["pref"]=> // string(8) "kanagawa" // } //} #県別の数量 $arr4 = _::countBy( $arr ,function( $ele ){ return ( $ele["age"] >= 20 ) ? "child": " adult "; } ); var_dump( $arr4 ); //array(2) { // ["child"]=> // int(3) // [" adult "]=> // int(2) //} #少し複雑なパターン $arr5 = _::countBy( $arr ,function( $ele ){ $age; if( $ele["age"] < 10 ){ $age ="jidou"; }elseif( $ele["age"] < 20 ){ $age ="teen"; }elseif( $ele["age"] < 30 ){ $age ="twenty"; }else{ $age ="adult"; } return $age; } ); var_dump( $arr5 ); //array(4) { // ["adult"]=> // int(2) // ["teen"]=> // int(1) // ["twenty"]=> // int(1) // ["jidou"]=> // int(1) //} // |
変換
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
#名前、メルアド(空白除去+ドメイン)の配列を作る $arr2 = _::map( $arr, function($ele) { $ele["email"] = trim( $ele["name"] ) ."@". $ele["domain"]; return $ele; }); var_dump( $arr2 ); //array(5) { // [0]=> // array(5) { // ["name"]=> // string(7) " kazumi" // ["domain"]=> // string(9) "gmail.com" // ["age"]=> // string(2) "30" // ["pref"]=> // string(5) "chiba" // ["email"]=> // string(16) "kazumi@gmail.com" // } // [1]=> // array(5) { // ["name"]=> // string(7) "ichirou" // ["domain"]=> // string(11) "yahoo.co.jp" // ["age"]=> // string(2) "18" // ["pref"]=> // string(5) "tokyo" // ["email"]=> // string(19) "ichirou@yahoo.co.jp" // } // [2]=> // array(5) { // ["name"]=> // string(8) " yuusuke" // ["domain"]=> // string(11) "hotmail.com" // ["age"]=> // string(2) "25" // ["pref"]=> // string(5) "chiba" // ["email"]=> // string(19) "yuusuke@hotmail.com" // } // [3]=> // array(5) { // ["name"]=> // string(8) " satoshi" // ["domain"]=> // string(9) "gmail.com" // ["age"]=> // string(2) "45" // ["pref"]=> // string(8) "kanagawa" // ["email"]=> // string(17) "satoshi@gmail.com" // } // [4]=> // array(5) { // ["name"]=> // string(6) "jirou " // ["domain"]=> // string(11) "hotmail.com" // ["age"]=> // string(1) "9" // ["pref"]=> // string(5) "tokyo" // ["email"]=> // string(17) "jirou@hotmail.com" // } //} // // // |
応用系(全てをチェーンでつなぐ)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
#30歳以上のメルアド(名前の空白を削除し、名前+@+domain)を作る $arr3 = _::chain($arr) ->filter( function( $ele ) { return $ele["age"] >= 30; }) ->map( function( $ele ) { $ele["email"] = trim( $ele["name"] ) ."@". $ele["domain"]; return $ele; }); var_dump( $arr3 ); //object(Underbar\Internal\Wrapper)#2 (2) { // ["value":"Underbar\Internal\Wrapper":private]=> // array(2) { // [0]=> // array(5) { // ["name"]=> // string(7) " kazumi" // ["domain"]=> // string(9) "gmail.com" // ["age"]=> // string(2) "30" // ["pref"]=> // string(5) "chiba" // ["email"]=> // string(16) "kazumi@gmail.com" // } // [3]=> // array(5) { // ["name"]=> // string(8) " satoshi" // ["domain"]=> // string(9) "gmail.com" // ["age"]=> // string(2) "45" // ["pref"]=> // string(8) "kanagawa" // ["email"]=> // string(17) "satoshi@gmail.com" // } // } // ["impl":"Underbar\Internal\Wrapper":private]=> // string(18) "Underbar\ArrayImpl" //} |
追記
group byは複数キーでも行けるようです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
$arr = [ ['class' => 'A', 'type'=>'2' , 'pref' => 'chiba'], ['class' => 'A', 'type'=>'3' , 'pref' => 'tokyo'], ['class' => 'A', 'type'=>'2' , 'pref' => 'chiba'], ['class' => 'B', 'type'=>'1' , 'pref' => 'tokyo'], ]; $arr2 = _::groupBy( $arr , function($ele) { return $ele["class"] ."_" . $ele['type'] ; } ); array(3) { 'A_2' => array(2) { [0] => array(3) { 'class' => string(1) "A" 'type' => string(1) "2" 'pref' => string(5) "chiba" } [1] => array(3) { 'class' => string(1) "A" 'type' => string(1) "2" 'pref' => string(5) "chiba" } } 'A_3' => array(1) { [0] => array(3) { 'class' => string(1) "A" 'type' => string(1) "3" 'pref' => string(5) "tokyo" } } 'B_1' => array(1) { [0] => array(3) { 'class' => string(1) "B" 'type' => string(1) "1" 'pref' => string(5) "tokyo" } } |
参考リンク