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)。这里有一堆不同的扁平化方法。只有包含forforeach执行显式循环的函数才会被包括在内以进行比较。

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仍然比普通for循环慢。我希望array_merge_recursive至少能快到甚至更快,因为它基本上将整个工作交给了一个 C 函数!

于 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 回答
0

目前,最简单的方法是使用 array_column() 函数

$newArray = array_column($array, 'id');
于 2020-01-29T13:08:10.573 回答