有序数组转换为关联数组,奇数值作为键

4
相当简单:
// turn
array('foo', 'bar', 'hello', 'world');

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

目前我正在使用:

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

我想知道是否有一种方法可以在不使用中间变量$arrayOut的情况下完成此操作。我可以编写一个函数,但这只是单个用例,我正在尝试保持我的脚本简洁。我只是想知道是否有我在文档中错过的东西可以达到这个目的。
这些值来自路由路径:
route/to/controller/action/key1/value1/key2/value2

它已经崩溃了,在使用其他组件后,我只剩下('key1', 'value1', 'key2', 'value2', ...)


感谢各位的见解和建议。 Long Ears 以简明扼要的方法赢得了胜利,当扩展到超过“1行”时,不会太神秘(至少我认为不会)

然而,也与 Long Ears 的建议有关,也许我的渴望用最少的冗余来保持语义上精确的代码已经让我失去了理智,我一直在追求无污染的变量范围,引用自己的话。


4个回答

5

您可以使现有代码略微更加高效(每次迭代删除一个函数调用,仅限于在开始时):

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

好的,(发抖)这里是您要的一句话:

$b = call_user_func_array('array_merge', array_map(function($v) { return array($v[0] => $v[1]); }, array_chunk($a, 2)));

感谢长耳朵;不错,虽然效率并不是问题,但作用域污染确实是一个问题。我一定会记住这个方法,用于更大数据的类似操作。 - Dan Lugg
2
@Tomcat 我会说如果智能提示(即Intellisense)抛出某种警告,则它太挑剔了。作为程序员,你的首要责任是使代码易于理解。偶尔这与第二个责任——使代码高效——相冲突。但是,两者都不应该被(可以争论的)美学所妥协。 - Long Ears
@长耳朵;非常好的观点。作为一名网页/平面设计师和开发人员,我有时会把自己的优先事项搞混。美学应该留给用户界面。 - Dan Lugg
@Tomcat已更新,包含我认为你正在寻找的内容,尽管我仍然坚持简单原则。 - Long Ears
@Long Ears:+1 因为我以前从未使用过 array_chunk :) 很好的版本! - Jon
显示剩余2条评论

3

您不需要数组,可以直接使用路径文本:

$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
)
*/

2
我认为你已经做得很好了。但是,当读取输入时,尝试将奇数和偶数元素放入不同的数组中怎么样?然后,您可以使用array_combine来制作一行代码。
更新:array_map无法帮助,因为它会产生具有相等数量元素的数组。您可以使用array_filter和array_combine进行操作,但这样做不会更短。
我真的很喜欢你所拥有的东西;简短,简单,实现了工作。我只是将其重构为一个函数,比如说array_interleave_combine之类的。
第二次更新:
好吧,你要求的,这就是它。如果你问我,它试图变得太聪明了。虽然这是一行代码,但我真的真的不认为这种“纯度”足以弥补某人需要理解发生了什么而失去的时间。
$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;
    });

谢谢Jon;嗯,array_combine可能可行。我在考虑使用array_map和lambda来保持我的方法范围干净;请参见编辑以获取详细说明。 - Dan Lugg
@TocmatExodus:在回答之前,我曾经考虑过这个问题。但我认为它简单地不可能比你现在已有的更短。 - Jon
@Jon; 我需要的不是“短”,而是非污染作用域,这就是为什么 lambda 很好的原因。我会试着调整一下。 - Dan Lugg
我认为你指的是13行代码 ;) - Long Ears
@长耳朵:请原谅,我只是太习惯向编译器发出指令了。 ;) - Jon

1
此解决方案不需要额外的数组:
$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]);
}

1
只要你的数组元素数量是偶数,@TomcatExodus 就不应该成为问题。为了确保,请使用条件 $i + 1 < $count - Jacob
1
我有点挑剔,但是尝试一下 $arr = array('1', 'bar', 'hello', 'world');;你就明白了。如果一个数组元素是之前未见过的整数的字符串表示形式,那么你将会丢弃它。 - Jon
@Jon:是的,这是它的一个缺点。我认为使用临时数组是最好的选择。 - user142162

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接