基于键范围将PHP数组拆分

6

我有一个数组。

    数组
    (
        [initial] => MSS
        [hour] => 5.2
        [row_checker_1] => 1
        [project_name_1] => KGD001
        [project_shortcode_1] => KGD001
        [5_1] => 23
        [6_1] => 3.3
        [4_1] => 23.2
        [remarks_1] => 在进行中
        [task_id] => 76
        [row_checker_2] => 2
        [project_name_2] => DG001
        [project_shortcode_2] => DG001
        [5_2] => 1.1
        [6_2] => 2.2
        [4_2] => 3.1
        [remarks_2] => 在进行中
    )

现在我想将所有元素拆分,上限键为"project_shortcode_1",下限键为remarks_1。

因此,新的数组应该如下所示:

    array
    (
        [5_1] => 23
        [6_1] => 3.3
        [4_1] => 23.2
    )


4
数组中的键可以以不同的顺序出现,你知道吗? - u_mulder
也许你只需要带有键 NUMBER_1 的值? - u_mulder
如果NUMBER_1可行,那将是完美的解决方案。 - user3074921
这是可能的,但我在这里没有看到任何代码尝试。如果你认为我们会为你编写代码 - 你错了。 - u_mulder
我只想知道,是否可以基于PHP数组索引键实现? - user3074921
@MohammadShahnewazSarker 是的,这是可能的,只要尝试一下就行了。 - Karim Harazin
4个回答

2

使用带有标志ARRAY_FILTER_USE_KEY的array_filter来使用数组键,并使用所需的逻辑进行比较以获取所需的键。它适用于PHP 5.6及以上版本。

$arr = array ( "initial" => "MSS",
        "hour" => 5.2,
        "row_checker_1" => 1,
        "project_name_1" => "KGD001",
        "project_shortcode_1" => "KGD001",
        "5_1" => 23,
        "6_1" => 3.3,
        "4_1" => 23.2,
        "remarks_1" =>  "on going",
        "task_id" => 76,
        "row_checker_2" => 2,
        "project_name_2" => "DG001",
        "project_shortcode_2" => "DG001",
        "5_2" => 1.1,
        "6_2" => 2.2,
        "4_2" => 3.1,
        "remarks_2" =>   "on going",
    );

// PHP > 5.6
$result = array_filter($arr, function($k){
    $var = explode('_', $k);
    return is_numeric($var[0]) && $var[1]==1;
}, ARRAY_FILTER_USE_KEY);

1
这是一篇不错的文章,但我想指出的是"7_1_gotcha"=> 666会被认为是结果数组的一部分,但实际上它不应该在那里。这是一个完全虚构的数组元素(猴子扳手)-- 我不知道这种方法漏洞实际上会引起多大麻烦。我的观点是:这就是不使用从头到尾的正则表达式模式的缺点。 - mickmackusa
好的观点。优化过滤条件(count($var) == 2)可以避免这种漏洞。我认为选择正则表达式模式解决方案是一个需要和性能的问题。 - Dez
1
我保证在这条评论后不再打扰你 ;) … "2e7_1" => 666 也会通过。这不是 explode() 的错误,而是 is_numeric() 宽容的倾向所致。 - mickmackusa
改进总是受欢迎的! :) 如果只期望整数,则使用 intval($var) == $var 进行检查可能会起作用。 - Dez
应该可以了。 - mickmackusa

2
如果你需要一个包含所有范围为NUMBER_N的多维数组,那么可以使用以下代码(扩展自Dmitriy Demir的答案):
$myArray = array(
    'initial' => 'MSS',
    'hour' => '5.2',
    'row_checker_1' => '1',
    'project_name_1' => 'KGD001',
    'project_shortcode_1' => 'KGD001',
    '5_1' => '23',
    '6_1' => '3.3',
    '4_1' => '23.2',
    'remarks_1' => 'on going',
    'task_id' => '76',
    'row_checker_2' => '2',
    'project_name_2' => 'DG001',
    'project_shortcode_2' => 'DG001',
    '5_2' => '1.1',
    '6_2' => '2.2',
    '4_2' => '3.1',
    'remarks_2' => 'on going'
);

function splitRange($a){
    $newArray = array();
    foreach ($a as $k => $v) {
        $rightFormat = preg_match('/^\d+_(\d+)$/', $k, $index);
        if ($rightFormat)
            $newArray[$index[1]][$k] = $v;
    }
    return $newArray;
}

print_r(splitRange($myArray));

结果将类似于:
    Array
(
    [1] => Array
        (
            [5_1] => 23
            [6_1] => 3.3
            [4_1] => 23.2
        )

    [2] => Array
        (
            [5_2] => 1.1
            [6_2] => 2.2
            [4_2] => 3.1
        )

)

从数组的索引NUMBER_N中获取N


1

既然您在评论中提到您更喜欢获取所有格式为NUMBER_1的值,我认为您需要循环遍历数组并使用正则表达式检查值名称,如果符合条件,则将值添加到新数组中。以下是我的做法:

$myArray = array(
    'initial' => 'MSS',
    'hour' => '5.2',
    'row_checker_1' => '1',
    'project_name_1' => 'KGD001',
    'project_shortcode_1' => 'KGD001',
    '5_1' => '23',
    '6_1' => '3.3',
    '4_1' => '23.2',
    'remarks_1' => 'on going',
    'task_id' => '76',
    'row_checker_2' => '2',
    'project_name_2' => 'DG001',
    'project_shortcode_2' => 'DG001',
    '5_2' => '1.1',
    '6_2a' => '2.2',
    '4_2' => '3.1',
    'remarks_2' => 'on going'
);

$newArray = array();
foreach ($myArray as $k => $v) {
    $rightFormat = preg_match('/^\d+_\d+$/', $k);
    if ($rightFormat)
        $newArray[$k] = $v;
}
print_r($newArray);

在这种情况下,print_r 的结果将是:

Array ( [5_1] => 23 [6_1] => 3.3 [4_1] => 23.2 [5_2] => 1.1 [6_2] => 2.2 [4_2] => 3.1 )

如果下划线后面的数字始终为1,则将正则表达式从/^\d+_\d+$/更改为/^\d+_1$/
您可以尝试一下,了解正则表达式的工作原理here
PS:我已经将所有值设置为字符串以方便使用。 随意修改。

我稍微修改了正则表达式:从 /\d+_\d//^\d+_\d$/,这可以确保像 5_1a 或者 a5_1 这样的键不会进入新数组。 - Dmitry Gamolin

1

这个问题似乎适合使用基于正则表达式的解决方案。

preg_grep() 是一个函数,旨在对数组中的每个值应用正则表达式过滤器。但是,在这种情况下,需要进行一些微调,因为必须过滤键而不是值。

一行代码解决:

$output=array_intersect_key($input,array_flip(preg_grep("/^\d+_1$/",array_keys($input)))));
/* array (
      '5_1' => 23,
      '6_1' => 3.3,
      '4_1' => 23.2,
    )*/

这是一步一步的数组操作...
array_keys($input);  // create array with input keys as values
/* array (
      0 => 'initial',
      1 => 'hour',
      2 => 'row_checker_1',
      3 => 'project_name_1',
      4 => 'project_shortcode_1',
      5 => '5_1',
      6 => '6_1',
      7 => '4_1',
      8 => 'remarks_1',
      9 => 'task_id',
      10 => 'row_checker_2',
      11 => 'project_name_2',
      12 => 'project_shortcode_2',
      13 => '5_2',
      14 => '6_2',
      15 => '4_2',
      16 => 'remarks_2',
   ) */

preg_grep("/^\d+_1$/",array_keys($input));  // filter the input array using regex pattern
/* array (
      5 => '5_1',
      6 => '6_1',
      7 => '4_1',
   ) */

array_flip(preg_grep("/^\d+_1$/",array_keys($input))); // flip the filtered array
/* array (
      '5_1' => 5,
      '6_1' => 6,
      '4_1' => 7,
   )*/

array_intersect_key($input,array_flip(preg_grep("/^\d+_1$/",array_keys($input))));  // filter input by comparing keys against filtered array
/* array (
      '5_1' => 23,
      '6_1' => 3.3,
      '4_1' => 23.2,
   )*/

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