【问题标题】:changing array keys in array_walk function?更改 array_walk 函数中的数组键?
【发布时间】:2012-11-07 13:42:17
【问题描述】:

我正在使用数组函数将我的管道分隔字符串转换为关联数组。

$piper = "|k=f|p=t|e=r|t=m|";

$piper = explode("|",$piper);

$piper = array_filter($piper);

function splitter(&$value,$key) {

    $splitted = explode("=",$value);
    $key = $splitted[0];
    $value = $splitted[1];

}

array_walk($piper, 'splitter');

var_dump($piper);

这给了我

array (size=4)
  1 => string 'f' (length=1)
  2 => string 't' (length=1)
  3 => string 'r' (length=1)
  4 => string 'm' (length=1)

我想去哪里:

array (size=4)
  "k" => string 'f' (length=1)
  "p" => string 't' (length=1)
  "e" => string 'r' (length=1)
  "t" => string 'm' (length=1)

但是键没有改变。是否有任何数组函数可以让我循环遍历数组并更改键和值?

【问题讨论】:

  • 想要的结果数组是什么?
  • @JasonMcCreary:我已经更新了
  • 编辑:“哪个最快”在我看来现在这不是一个建设性的问题。请参阅下面的评论。

标签: php arrays function


【解决方案1】:

array_walk的文档中说(描述回调函数):

只有数组的值可能会改变;它的结构 无法更改,即程序员无法添加、取消设置或重新排序 元素。如果回调不遵守此要求,则 此函数的行为未定义且不可预测。

这意味着您不能使用array_walk 来更改迭代数组的键。但是,您可以使用它创建一个新数组:

$result = array();
array_walk($piper, function (&$value,$key) use (&$result) {
    $splitted = explode("=",$value);
    $result[ $splitted[0] ] = $splitted[1];
});
var_dump($result);

不过,我想如果是我,我会在这里使用正则表达式(而不是“爆炸”):

$piper = "|k=f|p=t|e=r|t=m|";
preg_match_all('#([^=|]*)=([^|]*)#', $piper, $matches, PREG_PATTERN_ORDER);
$piper = array_combine($matches[1], $matches[2]);
var_dump($piper);

【讨论】:

  • 因为问题是关于“数组函数”的,我想展示如何做到这一点。我同意foreach 方法在这里更干净;不过,更重要的是,您仍然必须创建一个单独的数组来存储结果。我已经展示了我在这里选择的方法:对我来说,这比 foreaching 爆炸要好(事实上,我会首先尝试重新组织 parse_str 的输入以使其可用,但这可能是另一回事)。
  • @AlexandruMihai 我可以问一下,为什么这里的正则表达式解决方案应该是最慢的?仅仅因为它“通常”最慢?
  • @raina77ow:是的,因为应用正则表达式通常更耗时。由于您和我都没有花时间测试这个特殊情况,我敢打赌正则表达式解决方案会更慢。
  • @AlexandruMihai 你错过了这样一个事实,即 'explode' 将被调用的次数与这里的 'k=v' 令牌一样多,这使得它比单个 preg_match_all 调用更昂贵。在优化讨论中,“通常”是一个糟糕的词。
  • @mithunsatheesh:根据这篇文章willem.stuursma.name/2010/11/22/…,foreach 比 array_map 快,所以考虑到 array_walk 和 array_map 之间的功能相似性,我认为它也比 array_walk 快。
【解决方案2】:

为什么不从 $piper 构建一个包含所需键和值的新数组?

$piper2 = array();
foreach ($piper as $k => $val)
{
  $splitted = explode("=", $val);
  $key = $splitted[0];
  $value = $splitted[1];

  $piper2[$key] = $value;
}

$piper = $piper2; // if needed

【讨论】:

  • 请建议我哪一个执行得最快? foreach 或正则表达式还是 array_walk?
【解决方案3】:

您可以更好地使用foreach。下面的例子展示了处理一个条目,用右键添加它并删除原始条目。

$piper = "|k=f|p=t|e=r|t=m|";
$piper = array_filter(explode("|", $piper));

foreach ($piper as $index => $value) {
    list($key, $value) = explode("=", $value);
    $piper[$key] = $value;
    unset($piper[$index]);
}

注意不要有像索引一样的键。

另一种选择是通过引用处理值并在之后设置键:

foreach ($piper as &$value) {
    list($keys[], $value) = explode("=", $value);
}
unset($value);

$piper = array_combine($keys, $piper);

这不会给您带来任何麻烦,而只是使用重复的键。但是您可以在foreach 之后检查该问题,不会丢失任何数据。

以下foreach 无法保证的东西,这可能是最简化的结果数组:

$result = array();
foreach ($piper as $value) {
    list($key, $value) = explode("=", $value);
    $result[$key] = $value;
}

【讨论】:

  • @JasonMcCreary:我添加了第二个示例,它重新使用了更合适的值。无论如何,$piper 用于处理,所以我认为使用(而不是重复使用)它没有任何问题。
  • 请建议我哪一个执行得最快? foreach 或正则表达式还是 array_walk?
  • 我会选择foreach,因为它更直截了当并且清楚它的作用。对于所有答案,您不必关心哪个最快,在您的情况下所有答案都足够快。如果您关心速度,则需要衡量您的案例是否真的是毫秒的分数。
  • @hakre 我希望我也可以将此评论纳入我的回答线程。 )
【解决方案4】:

使用 array_reduce 就可以了

$piper = "|k=f|p=t|e=r|t=m|";

$piper = explode("|",$piper);

$piper = array_filter($piper);

function splitter($result, $item) {
    $splitted = explode("=",$item);
    $key = $splitted[0];
    $value = $splitted[1];

    $result[$key] = $value;

    return $result;
}

$piper = array_reduce($piper, 'splitter', array());

var_dump($piper);

基于此:http://www.danielauener.com/howto-use-array_map-on-associative-arrays-to-change-values-and-keys/

【讨论】:

    【解决方案5】:

    这是我的递归函数,它不仅可以将数组的值更改为 array_walk_recursive() ,还可以更改给定数组的键。它还保持数组的顺序: https://stackoverflow.com/a/57622225/10452175

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-30
      • 1970-01-01
      相关资源
      最近更新 更多