【问题标题】:How to keep only specific array keys/values in array?如何在数组中只保留特定的数组键/值?
【发布时间】:2014-06-03 05:10:12
【问题描述】:

我有一个多维数组,我正在搜索特定值。 如果找到这些值,我需要使用这些值提取索引(创建新数组)并删除所有其他值。

array_intersect 在 php 5.3 上运行良好,现在在 5.4 上它抱怨 注意:数组到字符串的转换。

我发现 array_intersect 在 5.4 上存在多维数组问题。 https://bugs.php.net/bug.php?id=60198

这是我正在搜索的 $options 数组

Array (

    [index1] => html
    [index2] => html
    [index3] => slide
    [index4] => tab
    [index5] => Array
        (
            [0] => 123
        )

)

适用于 php 5.3.x 的代码

$lookfor   = array('slide', 'tab');
$found     = array_intersect($options, $lookfor);


print_r($found);


Array
(
    [index3] => slide
    [index4] => tab
)

但在 5.4.x 中,这会引发上述错误。

请问还有什么方法可以在没有循环的情况下做到这一点。 并且没有抑制错误。

谢谢!

【问题讨论】:

  • 为什么不能使用当前的代码?您应该以任何方式禁止显示给最终用户的所有错误,并且不要记录这些。
  • 当你打字时,我编辑了我的帖子。我不想抑制错误。希望找到解决方案而不是通过@隐藏通知
  • 是什么阻止你只使用循环?
  • @Charles,$options 数组有 200 多个选项,因此我宁愿不循环遍历所有选项
  • 去做吧。然后使用 xdebug 或 xhprof 分析您的代码。我向你保证,仅仅循环一个包含 200 个元素的数组的行为在性能方面甚至不会是杯水车薪。你认为array_intersect(以及下面的array_filter是什么?

标签: php multidimensional-array


【解决方案1】:

array_intersect() 不是递归的。该函数假定数组只有一层深,并期望所有数组元素都是标量。当它找到一个非标量值,即一个子数组时,它会抛出一个通知。

这在documentation for array_intersect()中隐约提到:

注意:两个元素被认为相等当且仅当:(string) $elem1 === (string) $elem2。换句话说:当字符串表示相同时。

我能想到的一个解决方案是使用array_filter()

$lookfor = array('html', 'slide');
$found   = array_filter($options, function($item) use ($lookfor) {
    return in_array($item, $lookfor);
});

注意:这仍然执行循环,并不比简单的foreach 更好。事实上,如果数组很大,它可能会比foreach 慢。我不知道你为什么要避免循环——我个人认为如果你只使用循环会更干净。

Demo

我能想到的另一个解决方案是在使用 array_intersect() 之前删除子数组:

<?php

$options = array(
    'index1' => 'html',
    'index2' => 'html',
    'index3' => 'slide',
    'index4' => 'tab',
    'index5' => array(123),
);

$lookfor = array('html', 'slide');
$scalars = array_filter($options,function ($item) { return !is_array($item); });
$found = array_intersect ($scalars, $lookfor);

print_r($found);

Demo

【讨论】:

  • zwacky 提出了这个解决方案,但感谢您的解释。
  • @Benn:你为什么不想使用循环?
  • 我在上面的评论中提到,options 数组有超过 200 个选项。所以我有点想远离循环,一个班轮看起来更干净,更快。
  • @Benn:您是否阅读了我答案末尾的评论?大多数时候,foreach 可能会更快。对于大数组,array_*() 函数的峰值内存使用量可能是foreach 循环的 2.5 倍。
  • @Benn:一个更干净的解决方案可能是首先删除子阵列,之前使用array_intersectSee demo.
【解决方案2】:

你可以使用 array_filter()

$arr = array(
  'index1' => 'html',
  'index2' => 'html',
  'index3' => 'slide',
  'index4' => 'tab',
  'index5' => array(0 => 123),
);

$with = array('html', 'slide');
$res = array_filter($arr, function($val) use ($with) {
    return in_array($val, $with);
});

这将返回 index1、index2 和 index3。

编辑:只需阅读您的评论,您的数组将包含大量条目。 array_filter 当然会循环使用条件并创建一个新数组。

【讨论】:

  • 不错的一个。我看看有没有其他人想出更好的解决方案,但现在这个可行
  • Github 风格的降价在这里不起作用。您需要改用缩进方法(通过选择代码并按 Ctrl+K 或使用工具栏按钮即可轻松使用)
【解决方案3】:
$array = [
    'a' => 4,
    's' => 5,
    'd' => 6,
];
$onlyKeys = ['s','d'];

$filteredArray = array_filter($array, function($v) use ($onlyKeys) {
    return in_array($v, $onlyKeys);
}, ARRAY_FILTER_USE_KEY);

prinr_r($filteredArray); //  ['s' => 5, 'd' => 6]

要按值过滤,请从参数列表中删除 ARRAY_FILTER_USE_KEY。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-22
    • 1970-01-01
    • 2022-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-10
    相关资源
    最近更新 更多