9

ここにデータがあります

$array = array(
    'random' => 1,
    'pewpew' => 2,
    'temp' => 5,
    'xoxo' => 3,
    'qweqweqe' => 4,
);

$fields = array('random', 'xoxo', 'temp');

私は結果を得る必要があります:

$result = array(
    'random' => 1,
    'xoxo' => 3,
    'temp' => 5,
);

$fields からのキーの存在/順序が $array に適用されることを意味します。

問題は、array_ 関数のみを使用してこの変換を実行できるかどうかです。(イテレーションは使いたくない) もしそうなら: 必要な関数をリンクしてもらえますか?

(スペルミスすみません)

更新。

PHP5.2

4

14 に答える 14

5
$result=array_intersect_key($array ,array_flip($fields) );
于 2012-06-29T16:12:03.240 に答える
3
// little trick required here...
$fields = array('random' => 0, 'xoxo' => 0, 'temp' => 0);
$result = array_intersect_key($array,$fields);
于 2012-06-29T16:07:22.947 に答える
2

私は常に、効率的なコード(コードの使用と速度の両方) に関するこの種の質問に興味があります。とはいえ、いくつかの異なる方法を試してベンチマークしましたが、これほど効率的でシンプルなものはありませんでしたforeach

投稿されたすべてのソリューションと、独自のarray_walkと基本的なforeachを試しました。Miraage によって投稿された配列とフィールドの両方を使用して、いくつかのテストをいくつか実行しました。また、$fields に $array にない値が含まれている場合に値が追加されるなど、結果に奇妙な点があることにも気付きました。

速攻で注文しました。

FOREACH: 0.01245 秒

$result = array();
foreach ($fields as $k)
{
    if (isset($array[$k]))
        $result[$k] = $array[$k];
}

ARRAY_DIFF_KEY: 0.01471 秒(予期しない結果: 追加の値)

$result = array_diff_key($fields, $array);

FOREACH (関数): 0.02449 秒

function array_filter_by_key($array, $fields)
{
    $result = array();
    foreach ($fields as $k)
    {
        if (isset($array[$k]))
            $result[$k] = $array[$k];
    }

    return $result;
}

ARRAY_WALK (参照による): 0.09123 秒

function array_walk_filter_by_key($item, $key, $vars)
{
    if (isset($vars[1][$item]))
        $vars[0][$item] = $vars[1][$item];
}

$result = array();
array_walk($fields, 'array_walk_filter_by_key', array(&$result, &$array));

リスト/各: 0.12456 秒

$result = array();
reset($fields);
while (list($key, $value) = each($fields))
{
    if (isset($array[$value]))
        $result[$value] = $array[$value];
}

ARRAY_INTERSECT_KEY: 0.27264 秒(順序が正しくありません)

$result = array_intersect_key($array, array_flip($fields));

ARRAY_REPLACE (array_intersect_key 秒): 0.29409 秒(予期しない結果: 追加の値)

$result = array_replace(
    array_fill_keys($fields, false),
    array_intersect_key($array, array_flip($fields))
);

ARRAY_REPLACE (2 つの array_intersect_key): 0.33311 秒

$flip = array_flip($fields);
$result = array_replace(
    array_intersect_key($flip, $array),
    array_intersect_key($array, $flip)
);

ARRAY_WALK (null を設定): 3.35929 秒(予期しない結果: 追加の値)

function array_walk_filter_by_key_null(&$item, $key, $array)
{
    if (isset($array[$key]))
        $item = $array[$key];
    else
        $item = null;
}

$result = array_flip($fields);
array_walk($result, 'array_walk_filter_by_key_null', $array);

ARRAY_REPLACE (array_intersect_key が最初): 11.11044 秒

$flip = array_flip($fields);
$result = array_intersect_key(
    array_replace($flip, $array),
    array_intersect_key($flip, $array)
);

ARRAY_MERGE: 14.11296 秒(予期しない結果: 追加の値)

$result = array_splice(
    array_merge(array_flip($fields), $array),
    0,
    count($fields)
);

それで、それはあります。DIYには勝てません。組み込み関数の方が高速であるという認識がある場合もありますが、常にそうであるとは限りません。最近のコンパイラはかなり優れています。

于 2012-07-08T12:37:08.307 に答える
1

パズルを解くためだけに:

$result = array_replace(
  array_intersect_key(array_flip($fields), $array),
  array_intersect_key($array, array_flip($fields))
);

最初のarray_intersectはフィールドのリストを適切な順序で作成し、もう1つはarray_replace機能を克服して、最初の配列に存在しないキーを作成します。

要件を満たしています。しかし、これはかなり重いかもしれないので、私はどのプロダクションコードでもそれを使用しません(私はベンチマークをしなかったので、それはただの直感です)。array_walkソリューションはより軽いようです。

于 2012-07-04T23:08:38.493 に答える
1

このコードは順序を保持し、必要に応じてPHP5.2で機能します

1行:

$result = array_merge( array_flip($fields),
                       array_intersect_key(
                                          $array,
                                          array_flip( $fields )
                                          )
                       );

パフォーマンスについて:

$flip = array_flip($fields);
$result = array_merge( $flip
                       array_intersect_key(
                                          $array,
                                          $flip
                                          )
                       );
于 2012-07-09T10:16:32.383 に答える
1

これは必要に応じて機能すると思います。

$result = array_splice(array_merge(array_flip($fields) , $array) , 0 , count($fields));
于 2012-07-04T17:19:18.463 に答える
0

$fieldsこれは、一部がキーとして存在しない場合も処理するソリューションです$array

$flip = array_flip($fields);
$result = array_intersect_key(array_replace($flip, $array), array_intersect_key($flip, $array));

すべて$fieldsがキーとして存在することがわかっている場合$arrayは、次の簡単な解決策があります。

$flip = array_flip($fields);
$result = array_intersect_key(array_replace($flip, $array), $flip);

これは次のようにワンライナーとして書くことができます:

$result = array_intersect_key(array_replace($flip=array_flip($fields), $array), $flip);

一部$fieldsがのキーではないがカウント$array$array含まれている場合、欠落しているキーのカウントを返すことが理にかなっている場合は、次のよう0に置き換えることができflip()ますarray_fill_keys($fields, 0)

$result = array_intersect_key(array_replace($fill=array_fill_keys($fields, 0), $array), $fill);

必要に応じて、これを適用してsを再度array_filter()除外できます。またはに0置き換えること0で、値がカウントされない場合にキーがないことにフラグを立てて処理できます。falsenull$array

悲しいことに、これらのソリューションは、このページの他のすべてのソリューションと同様に、のすべてのキーを処理する必要がありますが、$array明示的なループはオンになり$fieldsます。当面は、明示的なループほど高速な配列関数ベースのソリューションがないcount($array)場合よりもはるかに大きい場合のようです(コールバック関数で結果を明示的に構築するため、ここでは明示的なループと見なします)。count($fields)array_walk()array_reduce()

問題は、使用可能な関数のいずれもキーと値の間の関連付けを壊さないことです。また、の値を維持しながら、その並べ替え順序を保持するために、、またはその反転配列array_をループしたいので、ラック。$fields$array

于 2012-07-06T22:22:13.213 に答える
0

入力 ($array も $fields も) を変更することはできないと考えます。

これは、$fields の値をキーとして使用する配列がある場合に実現できます。その後、2 つをマージして ($fields を最初のパラメーターとして)、余分な要素を削除できます。

$fields を変更できないことを考慮して、作成します。

$tmp = array_combine($fields, range(1, count($fields)));
$result = array_merge($tmp, $array);
$result = array_splice($result, 0, count($fields));

完全な作業サンプル (いくつかのコメントを含む) は、http: //codepad.org/H0CDN7okにあります。

于 2012-07-04T12:57:22.270 に答える
0

私の試み:

    array_replace(
            array_fill_keys($fields, false),
            array_intersect_key($array,             # Keys in array, without order
                    array_flip($fields))));

$array と同じ順序でキーを取得するのは簡単でした。次に、それらを適切な順序で取得するために、$fields に等しいキーを持つ配列を作成しました。Array_replace が残りを行いました。

$array の不足しているキーが FALSE に置き換えられるため、必要に応じて除外できるという点で、ソリューションは「安定」しています。

array_flip はサイズ N のフィールド配列を 1 回歩き、array_intersect は N サイズの配列を M 回歩き、array_fill_keys のコストは N で、最終的な array_replace は N^2 だと思います。

したがって、総コストは M*N^5 です。

最小の配列をたどって大きな配列から値を選択するのは O(M^2*N^2) であるため、NI の値が大きい場合は、PHP ソリューションの方が高速であることが証明される可能性があります。これは、データ配列にないキーを入力しません。

   $answer = array();
   foreach($fields as $fld)     // N-sized cycle
       if (isset($array[$fld])) // Cost M
           $answer[$fld] =      // Assignment is N*1/2
               $array[$fld];    // Getting value is another M

(しばらくして、かなり困惑します)

私はチェックを実行しましたが、私が取得している時間はまったく無意味であるため、愚かな間違いを犯しているに違いないと思います. 確かに、私は非常に短い $fields 配列を使用しているため、歪んだ結果が予想されますが、これは歪んでいません。$answer[$fld] が非常に巧妙なハッシュ トリックで計算されない限り、解釈されたソリューションの真のコストは O(M^2*N^2) ではなく、K が小さい O(K*N^2) になります。

誰かが時間で遊びたい、または私が犯したかもしれない愚かな間違いを教えてくれるなら、これがベンチマークです.

他の明白な説明は、私がどこかでばかげた、ばかげた間違いを犯し、顔に卵をつけてしまうということであるため、私はこれを投稿することについて2つの考えを持っていました.

    $array = array(
        'random' => 1,
        'pewpew' => 2,
        'temp' => 5,
        'xoxo' => 3,
        'qweqweqe' => 4,
    );
    $fields = array('random', 'xoxo', 'temp');
    // Let's not print anything just yet, maybe that's what screwing the timer?
    $results = '';
    $duh = 0;

    for ($cycle = 0; $cycle < 10; $cycle++)
    {
            // Add some more elements to $array.
            for ($i = 0; $i < 10000; $i++)
            {
                    $k = uniqid();
                    $array[$k] = 42;
            }
            $start  = explode(' ', microtime());
            // WTF? Do more cycles to average the timing.
            for ($j = 0; $j < 10; $j++)
            {
                    // 0 or 1 to switch
                    if (1)
                    {
                    // INTERPRETED ANSWER
                    $answer = array();
                    foreach($fields as $fld)     // N-sized cycle
                       if (isset($array[$fld])) // Cost M
                           $answer[$fld] =      // Assignment is N*1/2
                               $array[$fld];    // Getting value is another M
                    } else {
                    // FUNCTION ANSWER
                    $answer = array_replace(
                            array_fill_keys($fields, false),
                            // array_combine($fields, $fields),
                            array_intersect_key($array,             # Keys in array, without order
                                    array_flip($fields)));
                    }
                    // USE $answer so to avoid premature optimization?
                    // You can't be that clever.
                    $duh += strlen(serialize($answer));
            }
            $stop   = explode(' ', microtime());
            // An error in timing? Check via a stupid roundabout.
            $int    = $stop[1]-$start[1]+1;
            $int    += ($stop[0]-$start[0]);
            $int    -= 1;
            $elapsed = number_format($int * 1000000, 2);
            $results        .= "".(5000*$cycle)." = $elapsed us.\n";
    }

    // I need to get in result:
    $wanted = array(
        'random' => 1,
        'xoxo' => 3,
        'temp' => 5,
    );
    // DID we get the right answer?
    print "Wanted:\n"; print_r($wanted);
    print "Gotten:\n"; print_r($answer);
    print "Results: $results\n$duh -- count of array is " . count($array);

    // And yet I have always the same realtime, name of a dog, how can that be?
    // I must be doing something REALLY REALLY wrong somewhere.
于 2012-07-06T20:28:00.827 に答える
0

簡単な方法:

$array = array(
   'random' => 1,
        'pewpew' => 2,
        'temp' => 5,
        'xoxo' => 3,
        'qweqweqe' => 4,
);

$fields = array('random', 'xoxo', 'temp');

$output = array();

foreach ($fields as $value) 
    if(isset($array[$value]))
         $output[$value]=$array[$value];            
于 2012-07-09T11:29:10.920 に答える
0

からのキーの順序を維持したい場合は$fields、これを試すことができます: (キーが に存在しない場合$array、そのキーの値は null になります。)

$result = array_flip($fields);
array_walk($result, function(&$item, $key, $array) {
  $item = isset($array[$key]) ? $array[$key] : null;
}, $array);

var_dump($result);
于 2012-07-03T02:33:59.050 に答える
0

PHP 関数はarray_diff_keyと呼ばれます。

サンプルコード:

$array = array(
    'random' => 1,
    'pewpew' => 2,
    'temp' => 5,
    'xoxo' => 3,
    'qweqweqe' => 4
);

$fields = array('random', 'xoxo', 'temp');
$result = array_diff_key($fields, $array);

これにより、目的の結果が得られます。

デモ: http://shaquin.tk/experiments/array1.php

編集:$fieldsのキーではない値を含めることができる場合は、次の$arrayコードを使用します。

$result = array_diff_key($fields, $array);
$result = array_intersect_key(array_flip($fields), $array);
$result = array_flip(array_diff(array_keys($result), $array));
$result = array_replace($result, $array);
$result = array_flip(array_intersect(array_flip($result), $fields));

これを少し最適化することは可能かもしれませんが、うまくいきます!

注: 私の (ホストされている) サイトには >= PHP 5.3 がないため、例にリンクすることはできませんが、同様のサイトにリンクできます: http://shaquin.tk/experiments/array2.php

于 2012-07-08T11:03:56.507 に答える
-1

これは機能し、順序を維持します。

$fields = array_flip($fields);
array_merge($fields,array_intersect_key($array, $fields));
$fields = array_keys($fields);

array_flipを2回呼び出すこともできますが、上記は少し「クリーン」に見えます。

于 2012-07-03T15:25:56.977 に答える
-1

試す:

$result=array();
reset($fields);
while(list($key,$value)=each($fields))
{
    if(isset($array[$value])) $result[$value]=$array[$value];
}
于 2012-06-29T16:03:19.187 に答える