使用一个扁平的白名单数组,从一个关联对象数组中移除元素。

10
我需要使用一个扁平的白名单值数组来过滤一个对象数组。
$objects = [
    3 => (object) ['tid' => 3],
    12 => (object) ['tid' => 12],
    9 => (object) ['tid' => 9],
];

$whitelist = [3, 4, 9, 11];

白名单中不包含12,所以应该将该对象移除。
[
    3 => (object) ['tid' => 3],
    9 => (object) ['tid' => 9],
]

这看起来像是一道作业题...如果不是的话请提前谅解。无论如何,你已经尝试过什么了吗? - Brian Driscoll
1
你所说的想要的和你想要的结果是相反的。 - Galen
第一个数组中不包含值 12?为什么第二个数组的第二个元素被移除了? - Felix Kling
Brian - 不要作业,Drupal的API结果可以。糟糕的数组技能。Galen - 可能是措辞的问题吗?在我的脑海中听起来没问题... - Russell
Felix - 第二个数组正在根据第一个数组进行过滤。第二个数组包含3、12、9。第一个数组不包含12,因此应该从第二个数组中删除12。 - Russell
@roosta:啊,我明白了...抱歉,是我的错。 - Felix Kling
6个回答

9
你可以这样做:
$keys = array_map(function($val) { return $val['value']; }, $first);
$result = array_intersect_key(array_flip($keys), $second);
array_map函数将从$first中提取出,使$keys成为这些值的数组。然后使用array_intersect_key函数获取$keys(翻转以使用键作为值,反之亦然)与第二个数组$second的交集。

问题的细节自您回答后已经发生了重大变化,请考虑更新这个答案。 - undefined

7

经过一些整理,我清楚地知道我需要什么了,这个小技巧可以解决:

foreach ($second_array as $foo) {
  if (!in_array($foo->tid, $first_array)) {
    unset($second_array[$foo->tid]);
  }
}   

5

对于关联数组,可以使用简单的键名白名单过滤:

$arr = array('a' => 123, 'b' => 213, 'c' => 321); 
$allowed = array('b', 'c'); 

print_r(array_intersect_key($arr, array_flip($allowed))); 

将返回:

Array 
( 
    [b] => 213 
    [c] => 321 
)

4

如果你想通过另一个数组中包含的所有键来筛选出你的数组,你可以使用array_filter函数。

$first  = [3,4,9,11];
$second = [ 3 => 'A' , 9 => 'B' , 12 => 'C'];

$clean = array_filter($second, function($key)use($first){
            return in_array($key,$first);
          },
           ARRAY_FILTER_USE_KEY);

// $clean = [ 3 => 'A' , 9 => 'B'];
< p > ARRAY_FILTER_USE_KEY 常量是函数的第三个参数,因此在回调函数中 $key 实际上是 $second 数组的键名。可以进行调整:

Flag determining what arguments are sent to callback (3rd argument):

ARRAY_FILTER_USE_KEY - pass key as the only argument to callback instead of the value
ARRAY_FILTER_USE_BOTH - pass both value and key as arguments to callback instead of the value

Default is 0 which will pass value as the only argument to callback instead.


1
虽然这段代码可能回答了问题,但提供有关它如何以及/或为什么解决问题的附加上下文将改善答案的长期价值。 - Nic3500
@Nic3500,你说得对,我改进了我的答案。感谢你的建议。 - Adam

3

array_filter中使用回调函数

如果你的第一个数组看起来像这样,你可能想将它改为更可用的一维数组,这样你就可以使用简单的in_array作为回调函数的一部分:

$values = array_map('reset',$array);

我现在才意识到键和对象ID是相似的:

$result =  array_intersect_key($objectarray,array_flip(array_map('reset',$array)));

这正是我一直在苦苦挣扎的问题。回调函数中的 "return $arr['value']" 是我期望能够起作用的。 - Russell
PHP不喜欢在对象上调用reset。https://3v4l.org/JUX2S问题细节已更新,以更好地定义正在处理的数据。 - undefined

0
为了比较每个对象中的“tid”列值与白名单值,不需要翻转、提取列或迭代调用“in_array()”。调用“array_uintersect()”来比较不同深度的数组。自定义函数中的“$a”和“$b”可以来自任何输入数组,所以首先尝试访问对象属性,如果不存在,则可以安全地假设该值来自平面的白名单数组。
代码:(演示
$objects = [
    3 => (object) ['tid' => 3],
    12 => (object) ['tid' => 12],
    9 => (object) ['tid' => 9],
];

$whitelist = [3, 4, 9, 11];

var_export(
    array_uintersect($objects, $whitelist, fn($a, $b) => ($a->tid ?? $a) <=> ($b->tid ?? $b))
);

虽然如此,这个问题中的数据适合通过将objectArray的键与白名单数组的值进行比较来进行更快的计算。在这种情况下,最快的方法是翻转白名单并调用array_intersect_key()函数,这在之前的回答中已经演示过了。

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