Ordered array to associative array, odd values as

2019-04-09 10:41发布

Pretty straightforward:

// turn
array('foo', 'bar', 'hello', 'world');

// into
array('foo' => 'bar', 'hello' => 'world');

Right now I'm using:

do{
    $arrayOut[current($arrayIn)] = next($arrayIn);
}while(next($arrayIn));

I'm wondering if there's a way to do it without the intermediary variable, $arrayOut. I could write a function, however this is a single use case, and I'm trying to keep my script uncluttered. I'm just wondering if there's something I missed in the docs that would serve this purpose.


The values are coming from a routing path:

route/to/controller/action/key1/value1/key2/value2

It's exploded, and eventually after using the other components, I'm left with ('key1', 'value1', 'key2', 'value2', ...)


Thank you folks for the insight and suggestions. Long Ears won this one for the concise approach, which when expanded to more than "1 line", is not terribly cryptic (I don't think at least)

However, also with regard to Long Ears' suggestion, perhaps my desire for semantically precise code with minimal verbosity has gotten the better of me, and I was chasing daisies trying to keep my variable scope "pollutant-free", to paraphrase myself.

4条回答
Emotional °昔
2楼-- · 2019-04-09 11:10

I don't think you can do better than what you have. But what about trying to put the odd and even elements in different arrays when your input is read? You could then use array_combine to make an one-liner.

Update: array_map won't help, as it will produce an array with an equal number of elements. You can do things with array_filter and array_combine, but again, that won't end up being shorter.

I really like what you have; short, simple, does the job. I 'd simply refactor it out into a function, let's say array_interleave_combine or some such.

Update 2:

Well, you asked for it, so here it is. Tries to be too clever if you ask me. Is an one-liner, but I really really don't think the "pureness" of this is enough to pay back the lost time someone would need to understand what's going on:

$result = array_reduce(
    array('foo', 'bar', 'hello', 'world'),
    function($partial, $item) {
        static $nextKey;
        if ($nextKey === null) {
            $nextKey = $item;
        }
        else {
            $partial[$nextKey] = $item;
            $nextKey = null;
        }

        return $partial;
    });
查看更多
等我变得足够好
3楼-- · 2019-04-09 11:24

This solution does not need an additional array:

$arr = array('foo', 'bar', 'hello', 'world');

for($i = 0, $count = count($arr); $i < $count; $i += 2)
{
  $arr[$arr[$i]] = $arr[$i + 1];
  unset($arr[$i], $arr[$i + 1]);
}
查看更多
聊天终结者
4楼-- · 2019-04-09 11:29

You do not need an array, you can do it directly with the path text:

$path = "foo/bar/hello/world";

preg_match_all("#(?J)(?<key>[^/]+)/(?<val>[^/]*)#", $path, $p);
$params = array_combine($p['key'], $p['val']);

print_r($params);
/*
Array
(
    [foo] => bar
    [hello] => world
)
*/
查看更多
啃猪蹄的小仙女
5楼-- · 2019-04-09 11:30

You can make your existing code slightly more efficient (removes one function call per iteration, for one at the beginning:)

$b = array();
array_unshift($a, false);
while (false !== $key = next($a)) {
    $b[$key] = next($a);
}

Ok, (shudder) here's your one liner:

$b = call_user_func_array('array_merge', array_map(function($v) { return array($v[0] => $v[1]); }, array_chunk($a, 2)));
查看更多
登录 后发表回答