使用键数组过滤另一个数组,并保持“顺序”

时间:2018-10-04 20:04:22

标签: php arrays

我使用标准PHP编码进行了以下工作,涉及循环和事物。 但是,我确信我可以结合使用所有PHP数组函数来完成相同的算法:array_intersect *,array_fill *和co ...

我希望有人已经遇到了这种情况,并找到了一种快速的方法。

好,这是:

我有一个索引数组,我们称它为数据,它包含大量有关实体的信息,顺序显然并不重要,因为它毕竟是索引数组:

$data = [
    'title' => 'loops and things',
    'id' => '28fr2',
    'link' => 'https://blah',
    'itemid' => '28fr3',
    'quantity' => 3,
    //...
];

现在,我有一组其他数组,这些数组描述了我的数据数组的一个子集,例如:

$product = [
    'id',
    'title',
    'link'
];

$inventory = [
    'itemid',
    'quantity',
];

我追求的是类似的东西

array_intersect_key_while_we_keep_the_order($data, $product);

会给

[
    'id' => '28fr2',
    'title' => 'loops and things',
    'link' => 'https://blah'
]

array_intersect_key_while_we_keep_the_order($data, $inventory);

会给

[
    'itemid' => '28fr2',
    'quantity' => 3
]

array_intersect_key存在的问题是“顺序”来自源数组,而不是定义键列表的源。 使用foreaches显然很简单,但是我相信它可以更快地完成。我只是看不到。

2 个答案:

答案 0 :(得分:2)

非常简单

$data = [
    'title' => 'loops and things',
    'id' => '28fr2',
    'link' => 'https://blah',
    'itemid' => '28fr3',
    'quantity' => 3,
    //...
];
$product = [
    'id',
    'title',
    'link'
];

$res = array_merge(array_fill_keys($product, null),array_intersect_key($data, array_flip($product)));
print_r($res);

输出

Array
(
    [id] => 28fr2
    [title] => loops and things
    [link] => https://blah
)

Sandbox

它是如何工作的,这里的主要技巧是数组填充键和数组合并。通过使用这些,我们可以创建一个“模板”数组。因为合并具有相同键的2个数组将按第一个数组的顺序合并。因此,我们可以将第一个数组设置为$product的顺序,然后在合并到其中时,将“假”值替换为实际值,并保留顺序。

如果您愿意,也可以使用数组翻转(或数组填充键)的结果,但是它将是两行代码...:)

当然,我们必须使用数组翻转或数组填充键之类的东西来将$product的值更改为可用于数组相交键的键。

我同时使用了数组填充键和数组翻转功能,在这种情况下它们可以互换。例如,这样会更有效:

$map = array_fill_keys($product, null);
$res = array_merge($map,array_intersect_key($data, $map));
print_r($res);

Sandbox

但是这需要2行...我应该提到数组填充键比数组翻转更可取。没关系,因为数组相交键会过滤掉地图中未包含的所有内容。但这“更好”,因为映射数组的值是相同的,而当使用翻页时,它们是数字键,在某些情况下(但不是在这种情况下)使用起来会有点困难。

几乎可以,您可以像这样使用它

function ordered_array_intersect_key(array $data, array $map){
    return array_merge(($map = array_fill_keys($map, null)),array_intersect_key($data, $map));
}

我随意命名它,并在array_merge中使用内联赋值,您也可以吃蛋糕也可以吃(重复使用array_fill_keys并有1行)。我刚想出一个函数时会想到的东西。

Sanbox

享受!

更新

感谢mosh442提出的想法。您还可以使用array_walk来构建一个新的数组,如下所示:

$data = [
    'title' => 'loops and things',
    'id' => '28fr2',
    'link' => 'https://blah',
    'itemid' => '28fr3',
    'quantity' => 3,
    //...
];
$product = [
    'id',
    'title',
    'link'
];

$new = [];

array_walk($product, function($v,$k,$data) use (&$new){$new[$v] = $data[$v];},$data);

print_r($new);

输出

Array
(
    [id] => 28fr2
    [title] => loops and things
    [link] => https://blah
)

Sandox

我喜欢这样的问题,非常有趣。...

答案 1 :(得分:0)

您也可以使用array_filter

array_filter(
            $data,
            function ($key) use ($inventory) {return in_array($key,$inventory);} ,
            ARRAY_FILTER_USE_KEY
            );

如注释中所述,在PHP 5.6.0中添加了ARRAY_FILTER_USE_KEY标志