4

単純な多次元配列をさらに単純な配列に変えたいと思います。

これを回します:

Array
(
    [0] => Array
        (
            [id] => 123
        )
    [1] => Array
        (
            [id] => 456
        )
    ...
    [999] => Array
        (
            [id] => 789
        )
)

次のような配列に:

Array
(
    [0] =>  123
    [1] => 456
    ...
    [999] => 789
)

でループせずにやりたいforeachです。これはPHPで可能ですか?

foreachループですでに解決できる方法は次のとおりです。

$newArr = array();
foreach ($arr as $a) {
    $newArr[] = $a['id'];
}
$arr = $newArr;

ループせずにやりたいです。手伝ってくれますか?

4

3 に答える 3

6

関数型プログラミングや暗黙のループに近づきたいというあなたの願望には感心しますが、PHP はあなたにとって不適切な言語です。機能的なスタイルでは自然に表現されません。

このreset関数は配列の最初の要素を返すため、その関数を配列にマップできます。

array_map('reset', $array)

ただし、PHP では、最速の方法は単純なforループです ( foreach, ではありませんfor)。ここでは、フラット化のさまざまな方法を紹介します。for明示的なループを含み、実行する関数のみがforeach比較のために含まれています。

function flatten_for($arr) {
    $c = count($arr);
    $newarr = array();
    for ($i = 0; $i < $c; $i++) {
        $newarr[] = $arr[$i][0];
    }
    return $newarr;
}


function flatten_for_inplace($arr) {
    $c = count($arr);
    for ($i = 0; $i < $c; $i++) {
        $arr[$i] = $arr[$i][0];
    }
}


function flatten_foreach($arr) {
    $newarr = array();
    foreach ($arr as $value) {
        $newarr[] = $value[0];
    }
    return $newarr;
}

function flatten_foreach_inplace($arr) {
    foreach ($arr as $k => $v) {
        $arr[$k] = $v[0];
    }
}

function flatten_foreach_inplace_ref($arr) {
    foreach ($arr as &$value) {
        $value = $value[0];
    }
}

function flatten_map($arr) {
    return array_map('reset', $arr);
}

function flatten_walk($arr) {
    array_walk($arr, function(&$v, $k){$v = $v[0];});
}

function visitor($v, $k, &$a) {
    return $a[] = $v;
}

function flatten_walk_recursive($arr) {
    $newarr = array();
    array_walk_recursive($arr, 'visitor', $newarr);
    return $newarr;
}

function reducer($result, $item) {
    return $item[0];
}

function flatten_reduce($arr) {
    return array_reduce($arr, 'reducer', array());
}

function flatten_merge($arr) {
    return call_user_func_array('array_merge_recursive', $arr);
}

タイミングコードは次のとおりです。

function buildarray($length) {
    return array_map(function($e){return array($e);}, range(0, $length));
}

function timeit($callable, $argfactory, $iterations) {
    $start = microtime(true);
    for ($i = 0; $i < $iterations; $i++) {
        call_user_func($callable, call_user_func($argfactory));
    }
    return microtime(true) - $start;
}

function time_callbacks($callbacks, $argfactory, $iterations) {
    $times = array();
    foreach ($callbacks as $callback) {
        $times[$callback] = timeit($callback, $argfactory, $iterations);
    }
    return $times;
}

function argfactory() {
    return buildarray(1000);
}

$flatteners = array(
    'flatten_for', 'flatten_for_inplace', 'flatten_foreach',
    'flatten_foreach_inplace', 'flatten_foreach_inplace_ref',
    'flatten_map', 'flatten_walk', 'flatten_walk_recursive',
    'flatten_reduce', 'flatten_merge',
);

$results = time_callbacks($flatteners, 'argfactory', 1000);

var_export($results);

古い MacBook Pro (Core 2 Duo、2.66 GHz、8GB、PHP 5.3.15、Suhosin-Patch 付き) では、次の結果が得られます。

array (
  'flatten_for' => 12.793387174606,
  'flatten_for_inplace' => 14.093497991562,
  'flatten_foreach' => 16.71691608429,
  'flatten_foreach_inplace' => 16.964510917664,
  'flatten_foreach_inplace_ref' => 16.618073940277,
  'flatten_map' => 24.578175067902,
  'flatten_walk' => 22.884744882584,
  'flatten_walk_recursive' => 31.647840976715,
  'flatten_reduce' => 17.748590946198,
  'flatten_merge' => 20.691106081009,
)

forメソッドとメソッドの違いは、foreach配列が長いほど小さくなります。

驚くべきことに (私にとってはとにかく)単純なループflatten_mergeよりもまだ遅いです。基本的にジョブ全体を C 関数に引き渡すため、高速ではないにしても、少なくとも同じくらい高速になるforと予想していました。array_merge_recursive

于 2013-02-18T20:12:11.673 に答える
3

あなたはそれをすることができmapます:

$arr = array_map(function($element) {
    return $element['id'];
}, $arr);

おそらく内部的にループするためarray_map、ループせずに本当に実行できます。

$arr = array_reduce($arr, function($arr, $element) {
    $arr[] = $element['id'];
    return $arr;
});

しかし、ループしない理由はありません。実際のパフォーマンスの向上はなく、コードの可読性は間違いなく低下します。

于 2013-02-18T20:10:22.343 に答える