1

I am trying to group my array values based on the array keys then print the result in the UI. I am stuck here for hours now.

Here is the array I need to format:

Array
(
    [checklist1] => major
    [result_audit1] => 1
    [checklist2] => minor
    [result_audit2] => 2
    [checklist3] => pico
    [result_audit3] => 3
    [checklist4] => goodpoints
    [result_audit4] => 4
    [submit] => Submit Now
)

Here is what I have tried so far but it is misaligned and not a proper result of the array.

foreach($n_data as $key => $data)
    {
        $array['checklist'][$i] = array(
            'selected' => $n_data[$key],
            'result_audit' => $n_data[$key]
        );

        $i++;
    }

Desired array:

Array
(
    [checklist] => Array
        (
            [0] => Array
                (
                    [selected] => major
                    [result_audit] => 1
                    [origin] => checklist1
                )

            [1] => Array
                (
                    [selected] => minor
                    [result_audit] => 2
                    [origin] => checklist2
                )
))
8
  • 4
    Use a good structure for the source data should be the prefered way. Commented Sep 4, 2023 at 7:16
  • 1
    @Rob did you notice that $i was never declared in your snippet? You only ever tried to access it and increment it. LF00 is correct, you will have fewer headaches if you improve your html form -- this way the payload will be easier to access. Commented Sep 5, 2023 at 21:29
  • 2
    I think sscanf() offers the most elegant solution: 3v4l.org/aYY8E, but I cannot post an answer because this page is closed. Commented Sep 5, 2023 at 22:25
  • 2
    @Rob I do not endorse any of the answers below. nice_dev's is too hard to read. esQmo_ and Olivier's answers will break when you have mult-digit identifiers. lukas.j's answer is using too many loops. mousetail's answer lacks elegance. Please use my above snippet in your project if you are not going to improve your form structure. At the very least, remove name="submit" from your form button so that it's value is not included in the submission payload. Commented Sep 6, 2023 at 0:54
  • 1
    @mickmackusa Using sscanf() is a very good idea. I can see here that you like that function ;-) Commented Sep 7, 2023 at 7:28

6 Answers 6

1

Here is a way to do it:

$data = ['checklist1'=>'major', 'result_audit1'=>1, 'checklist2'=>'minor', 'result_audit2'=>2, 'submit'=>'Submit Now'];

$res = [];
foreach($data as $key=>$val)
{
    if(substr($key, 0, 9)=='checklist')
    {
        $i = substr($key, -1);
        $res['checklist'][] = ['selected'=>$val, 'result_audit'=>$data['result_audit'.$i], 'origin'=>$key];
    }
}

print_r($res);

Output:

Array
(
    [checklist] => Array
        (
            [0] => Array
                (
                    [selected] => major
                    [result_audit] => 1
                    [origin] => checklist1
                )

            [1] => Array
                (
                    [selected] => minor
                    [result_audit] => 2
                    [origin] => checklist2
                )

        )

)
Sign up to request clarification or add additional context in comments.

Comments

1

I tried something that can result what you need

$datas = array(
    'checklist1' => 'major',
    'result_audit1' => 1,
    'checklist2' => 'minor',
    'result_audit2' => 2,
    'checklist3' => 'pico',
    'result_audit3' => 3,
    'checklist4' => 'goodpoints',
    'result_audit4' => 4,
    'submit' => 'Submit Now'
);

$array = array();
$i = 0;
foreach($datas as $key => $data){
    if (strpos($key, "checklist") !== false) {
        $array['checklist'][$i] = array(
            'selected' => $datas[$key],
            'result_audit' => $n_data["result_audit".substr($key, -1)],
            'origin' => $key
        );
        $i++;
    }
}

//Test
var_export($array);

Here I iterate through $datas array and check if the key contains the string "checklist" and add a new entry to $array['checklist'] array with the desired format. The result_audit value is obtened by concatenating the string "result_audit" with the last character of the current key (index number).

Comments

1

Looking at the order and the alignment of your array, you can use array_chunk to split the array into chunks of 2 and then use array_walk to add the keys as you desire. Use array_splice to get rid of the submit key. Below is the compact code for the same.

Snippet:

<?php

$chunked['checklist'] = array_chunk(array_splice($n_data, 0, count($n_data) - 1), 2);
array_walk($chunked['checklist'], fn(&$v, $idx) => $v = ['selected' => $v[0], 'result_audit' => $v[1], 'origin' => 'checklist'. ($idx + 1)]);
print_r($chunked);

Live Demo

Comments

1

You can try something like this:

$n_data= [
    "checklist1" => "major",
    "result_audit1" => "1",
    "checklist2" => "minor",
    "result_audit2" => "2",
    "checklist3" => "pico",
    "result_audit3" => "3",
    "checklist4" => "goodpoints",
    "result_audit4" => "4",
    "submit" => "Submit Now",
];

$array = [];

foreach($n_data as $key => $data)
    {
        // extract the number after the key
        if (str_starts_with($key, "checklist")) {
            $array['checklist'][substr($key, strlen("checklist"))]["selected"] = $data;
            $array['checklist'][substr($key, strlen("checklist"))]["origin"] = $key;
        }
        elseif (str_starts_with($key, "result_audit")) {
            $array['checklist'][substr($key, strlen("result_audit"))]["result_audit"] = $data;
        } else { throw new Exception("Unexpected array key") }
    }

print_r($array);

Demo

5 Comments

You should throw Exception, not Error (which is reserved for internal PHP errors).
Why do you ask PHP to measure the length of checklist, then ask it to measure it again; and worse, your script does this "static string" length check on every iteration. I would not use this script.
@mickmackusa Would a magic number be better?
Caching the length ($length = strlen("checklist")) would technically be "better", but to be honest I do not recommend your snippet as a whole. I'd post an answer if the page was open.
@mickmackusa Calculating the length of a string has a negligible performance cost. I don't think separating it out would improve things much
1
$data = [
  'checklist1'    => 'major',
  'result_audit1' => 1,
  'checklist2'    => 'minor',
  'result_audit2' => 2,
  'checklist3'    => 'pico',
  'result_audit3' => 3,
  'checklist4'    => 'goodpoints',
  'result_audit4' => 4,
  'submit'        => 'Submit Now'
];

// Extract array entries where the key starts with 'checklist'
$checklists = array_filter(
  $data,
  fn($key) => str_starts_with($key, 'checklist'),
  ARRAY_FILTER_USE_KEY
);

// ... and loop over these entries
$result = array_map(
  function ($value, $key) use ($data) {
    preg_match('/(\d+)$/', $key, $match);   // Get the number at the end of the key
    return [
      'selected'     => $value,
      'result_audit' => $data['result_audit' . $match[1]],   // Get the 'result_audit...' value from $data
      'origin'       => $key,
    ];
  },
  $checklists,
  array_keys($checklists)
);

print_r($result);

Output:

Array
(
    [0] => Array
        (
            [selected] => major
            [result_audit] => 1
            [origin] => checklist1
        )

    [1] => Array
        (
            [selected] => minor
            [result_audit] => 2
            [origin] => checklist2
        )

    [2] => Array
        (
            [selected] => pico
            [result_audit] => 3
            [origin] => checklist3
        )

    [3] => Array
        (
            [selected] => goodpoints
            [result_audit] => 4
            [origin] => checklist4
        )

)

2 Comments

The capture group is not beneficial; it only bloats the populated array with redundant values.
It is also not beneficial to use two loops. Filtering and data grouping can be done within one loop.
0

Parse the digital suffix of each checklist key and isolate the integer as a temporary value. As you iterate, if you encounter checklist data, push a new subarray into the result array which includes the related result_audit value.

Code: (Demo)

$result = [];
foreach ($array as $k => $v) {
    if (sscanf($k, 'checklist%d', $integer)) {  // isolate integer only on "checklist" keyed elements
        $result['checklist'][] = [
            'selected' => $v,
            'result_audit' => $array["result_audit$integer"],
            'origin' => $k
        ];
    }
}
var_export($result);

If the elegance of this answer isn't immediately obvious, it makes only one function call per iteration and doesn't need to use a regular expression to parse the keys.

1 Comment

Up for this, I have applied that too to my code

Your Answer

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