3

は、私は、タグPHPでの関数型プログラミングのためにarray_filter()を使用するにはどうすればよいですか?

$all_tags = array('A', 'B', 'C'); 

の配列を持っていると私は$ _GET変数をURLのセットを作成してみたいと思います。
私がするリンクを希望:
'A'"index.php?x[]=A&x[]=C"
にリンク"index.php?x[]=B&x[]=C"
'B'へのリンクなど (私は簡単にあります知っている($ _GETは、「現在」の要素を除いた全ての要素を持つ配列です)これを実装する方法:実際にはもっと複雑な状況を簡素化しています)

私はこれを解決するためにarray_filter()を使いたいと思います。
は、ここに私の試みです:

function make_get ($tag) { return 'x[]=' . $tag; } 
function tag_to_url ($tag_name) { 
    global $all_tags; 

    $filta = create_function('$x', 'global $all_tags; return ($x != $tag_name);'); 
    return 'index.php?' . implode('&', array_map("make_get", array_filter($all_tags, "filta"))); 
} 
print_r(array_map("", $all_tags)); 

しかし、それは動作しません。私はおそらく、PHPのマップとフィルタがデータ構造自体を実際に変更し、関数型を使用せずにブール値を返すということに疑念を抱いています。

このコードをより簡潔にするための他の方法にも興味があります。 Iコメント(shown here)で得られた回答に基づいて

+0

so ...リンクが何であれ、リンクのコレクションからその特定のエントリを削除し、残りの値でURLを構築しますか? –

+0

これはおそらく次のようなものです:http://www.ideone.com/vVnWe? –

+0

@BradChristie:まったく – amindfv

答えて

1

何かが非常に、非常に新しいです - それは唯一の機能は、ファーストクラスと匿名関数が可能であったになったPHP 5.3にありました。

ご参考までに、create_function()を使用しないでください。実際には、グローバルネームスペース(は決してにガベージコレクションされません!)の新しい関数を定義し、その背後でeval()を使用しています。

あなたはPHP 5.3以上を持っている場合は、あなたがこれを行うことができますが:あなたはPHP < 5.3をお持ちの場合は

$all_tags = array('A', 'B', 'C'); 

function is_not_equal($a, $b) { 
    return $a != $b; 
} 

function array_filter_tagname($alltags, $name) { 
    $isNotEqualName = function($item) use ($name){ 
     return is_not_equal($item, $name); 
    }; 
    // array_merge() is ONLY to rekey integer keys sequentially. 
    // array_filter() preserves keys. 
    return array_merge(array_filter($alltags, $isNotEqualName)); 
} 

function make_url($arr) { 
    return 'input.php?'.http_build_query(array('x'=>$arr)); 
} 
$res = array_filter_tagname($all_tags, 'B'); 
print_r($res); 
print_r(make_url($res)); 

、あなたはあなたの閉鎖の代わりcreate_function()のクラス+オブジェクトを使用する必要があります。一般的に

class NotEqualName { 
    protected $otheritem; 
    function __construct($otheritem) { // with PHP 4, use "function NotEqualName($otheritem) {" 
     $this->otheritem = $otheritem; 
    } 
    function compare($item) { 
     return $item != $this->otheritem; 
    } 
} 

function array_filter_tagname_objectcallback($alltags, $name) { 
    $isNotEqualName = new NotEqualName($name); 
    return array_merge(array_filter($alltags, array($isNotEqualName,'compare'))); 
} 

、しかし、PHPは、機能的なスタイルに非常に適していない、とあなたの特定のタスクのためのarray_filter()を使用することは非常に慣用PHPではありません。 array_diff()はより良いアプローチです。

1

:基本的に

<?php 

    $all_tags = array('A', 'B', 'C'); 

    function tag_to_url($tag_name) 
    { 
    global $all_tags; 

    $remaining_tags = array_diff($all_tags, array($tag_name)); 
    return sprintf('index.php?%s', 
      http_build_query(array('x'=>array_values($remaining_tags)))); 
    } 

    echo tag_to_url('B'); // index.php?x%5B0%5D=A&x%5B1%5D=C 
         // basically: index.php?x[0]=A&x[1]=C 

、来るhttp_build_queryにそれを渡し、その後、(代わりに、フィルタリングの)アレイからエントリを削除するarray_diffを使用有効なURLで

+0

+1非常に良いアプローチです。私はそこにグローバルを使用していないことを心から祈っています。 :) – Jon

+0

@ジョン:OPが私に与えたもので働く。 ;-) –

2

ここでは別のアプローチです:

// The meat of the matter 
function get_link($array, $tag) { 
    $parts = array_reduce($array, function($result, $item) use($tag) 
          { 
           if($item != $tag) $result[] = 'x[]='.$tag; 
           return $result; 
          }); 
    return implode('&', $parts); 
} 

// Test driver 

$all_tags = array('A', 'B', 'C'); 

echo get_link($all_tags, 'A'); 
echo "\n"; 
echo get_link($all_tags, 'B'); 
echo "\n"; 
echo get_link($all_tags, 'C'); 
echo "\n"; 

それは単にarray_reduceに一度のコールだし、その後implodeクエリ文字列に一緒に結果を引っ張って。

+0

+1の副作用はありません。 'map(" x [] = "++"(filter(/ = tag_name)all_tags) 'のような短い答えはまだありません:) – amindfv

1

私はちょうど "なぜそれdoesnt仕事"の部分に答えるつもりです。

$filta = create_function('$x', 'global $all_tags; return ($x != $tag_name);'); 

ラムダ関数のスコープでは、tag_name変数は未定義です。さて、は、作成機能スコープ(tag_to_url)で定義されているです。 $ tag_nameはグローバルスコープにないため、ローカルのtag_to_urlスコープにあるため、ここでglobalキーワードを使用することはできません。あなたはグローバルスコープで変数を宣言することができますが、それはうまくいくかもしれませんが、機能的なアプローチが大好きだと思うなら、グローバル変数が好きですか?

トリッキーな文字列連結とvar_export($ tag_name)必要に応じてcreate_function()に渡しますが、目的を達成するためのより良い方法があります。

また、私はあなたが開発中にPHPのエラー報告レベルを上げることによって利益を得るかもしれないと推測しています。 PHPは未定義の変数通知を投げてしまい、デバッグや理解に役立ちます。 PHPで関数型プログラミングスタイルのための本当の支援に近づい

// ideally set these in php.ini instead of in the script 
error_reporting(E_ALL); 
ini_set('display_errors', 1); 
関連する問題