6

I've an array.

    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
    )

Now I want to split all element upper range key is "project_shortcode_1" and lower range key is remarks_1.

So, new array should look like:

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

6
  • 4
    You know that keys in array can be in different order? Commented Nov 20, 2016 at 8:58
  • Maybe you just need values with keys NUMBER_1? Commented Nov 20, 2016 at 8:59
  • If NUMBER_1 possible it would be perfect solution. Commented Nov 20, 2016 at 9:01
  • It is possible but I don't see any code attempts here. If you think that we will write code for you - you're wrong. Commented Nov 20, 2016 at 9:03
  • I just want to know, if it possible based on php array indexing key ? Commented Nov 20, 2016 at 9:05

4 Answers 4

2

Use array_filter with flag ARRAY_FILTER_USE_KEY for using the array keys, and do the comparison with the logic needed to get the desired keys. It works from 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);
Sign up to request clarification or add additional context in comments.

5 Comments

This is a good post, but I just want to flag that "7_1_gotcha"=> 666 will qualify for the result array but shouldn't be there. This is a totally fabricated array element (monkey wrench) -- I don't know how likely it is that this method vulnerability will actually cause trouble. My point is: this is the downside to not using a start-to-finish regex pattern.
Good point. Refining the filter conditions (count($var) == 2) avoids that vulnerability. I think it is a matter of needs and performance to choose a regex pattern solution.
I promise to leave you alone after this comment ;) ... "2e7_1" => 666 will also pass. This is not a fault of explode() but of is_numeric()'s forgiving tendencies.
Improvements are always welcome! :) Then if only integers are expected a check with intval($var) == $var might do the work.
That should do it.
2

If what you need is a multidimensional array with all the ranges NUMBER_N, then use something like this (extended from Dmitriy Demir answer):

$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));

The result will be something like:

    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
        )

)

being N from NUMBER_N the index of the array.

Comments

1

Since you mentioned in the comments that you'd prefer to get all values that are in format NUMBER_1 I think you'd need to loop through your array and check the value names with regex, then add the values to a new array if they meet the criteria. Here's how I would do this:

$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);

The result of print_r in that case would be:

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

If the number after the underscore should always be 1 then change the regex from /^\d+_\d+$/ to /^\d+_1$/.

You can play around and see how regex works here.

PS: I've set all values to strings out of convenience. Feel free to modify that.

1 Comment

I've modified the regex a bit: from /\d+_\d/ to /^\d+_\d$/, this makes sure that keys like 5_1a or a5_1 won't get into the new array.
1

A regex-based solution seems fitting for this question.

preg_grep() is a function designed to apply a regex filter upon each value in an array. I little more tweaking is necessary for this case because the keys must be filtered instead.

The One-liner:

$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,
    )*/

Here is the step-by-step array manipulation...

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,
   )*/

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.