简体   繁体   中英

Group multidimentional array with 3 index PHP

I am not sure if I can explain this correctly but i will try,

I have a multidimensional array which looks like the array below. Notice changes in GROUPINDEX , ELOCATRIND and UNITINDEX . I tried a lot of looping, merge and filtering but couldn't able to achieve the desired result.

Array
(
[0] => Array
    (
        [GROUPINDEX] => 1
        [GROUPDESC] => Grading Parameters
        [UNITINDEX] => 1
        [ELOCATRIND] => 1
        [ELOCATRDES] => Grading Date
        [ELOCATRVAL] => 123
        [CODEDESC] => 
    )

[1] => Array
    (
        [GROUPINDEX] => 1
        [GROUPDESC] => Grading Parameters
        [UNITINDEX] => 2
        [ELOCATRIND] => 1
        [ELOCATRDES] => Grading Decider
        [ELOCATRVAL] => abc
        [CODEDESC] => 
    )

[2] => Array
    (
        [GROUPINDEX] => 1
        [GROUPDESC] => Grading Parameters
        [UNITINDEX] => 5
        [ELOCATRIND] => 1
        [ELOCATRDES] => 
        [ELOCATRVAL] => test-DE
        [CODEDESC] => 
    )

[3] => Array
    (
        [GROUPINDEX] => 1
        [GROUPDESC] => Grading Parameters
        [UNITINDEX] => 1
        [ELOCATRIND] => 2
        [ELOCATRDES] => Grading Date
        [ELOCATRVAL] => 123-2
        [CODEDESC] => 
    )

[4] => Array
    (
        [GROUPINDEX] => 1
        [GROUPDESC] => Grading Parameters
        [UNITINDEX] => 2
        [ELOCATRIND] => 2
        [ELOCATRDES] => Grading Decider
        [ELOCATRVAL] => abc-2
        [CODEDESC] => 
    )

[5] => Array
    (
        [GROUPINDEX] => 2
        [GROUPDESC] => Genre Codes
        [UNITINDEX] => 1
        [ELOCATRIND] => 1
        [ELOCATRDES] => Grading Date
        [ELOCATRVAL] => 2017-02-01
        [CODEDESC] => 
    )

[6] => Array
    (
        [GROUPINDEX] => 2
        [GROUPDESC] => Genre Codes
        [UNITINDEX] => 2
        [ELOCATRIND] => 1
        [ELOCATRDES] => Grading Decider
        [ELOCATRVAL] => NGR
        [CODEDESC] => 
    )
)

I need to group them in hierarchical order according to the above mentioned indexes. the final result should look like this:

Array
(
[0] => Array
    (
        [GROUPINDEX] => 1
        [GROUPDESC] => Grading Parameters
        [UNITINDEX] => 1
        [ELOCATRIND] => 1, 2
        [ELOCATRDES] => Grading Date:123 | Grading Date : 123-2

    )

[1] => Array
    (
        [GROUPINDEX] => 1
        [GROUPDESC] => Grading Parameters
        [UNITINDEX] => 2
        [ELOCATRIND] => 1, 2
        [ELOCATRDES] => Grading Decider:abc| Grading Decider:abc-2
    )

[2] => Array
    (
        [GROUPINDEX] => 1
        [GROUPDESC] => Grading Parameters
        [UNITINDEX] => 5
        [ELOCATRIND] => 1
        [ELOCATRDES] => 
        [ELOCATRVAL] => test-DE
        [CODEDESC] => 
    )


[5] => Array
    (
        [GROUPINDEX] => 2
        [GROUPDESC] => Genre Codes
        [UNITINDEX] => 1
        [ELOCATRIND] => 1
        [ELOCATRDES] => Grading Date
        [ELOCATRVAL] => 2017-02-01
        [CODEDESC] => 
    )

[6] => Array
    (
        [GROUPINDEX] => 2
        [GROUPDESC] => Genre Codes
        [UNITINDEX] => 2
        [ELOCATRIND] => 1
        [ELOCATRDES] => Grading Decider
        [ELOCATRVAL] => NGR
        [CODEDESC] => 
    )
)

I tried following snippet after some sanitization but it didn't work, and now I am out of ideas.

$result1 = array_map(
    function ($id) use ($Array) {
       return array_map(function ($data) {
            if (is_array($data)) return join(" | ", array_unique($data));
            return $data;
        }, array_reduce(
                array_filter($Array, function ($item) use ($id) { return $id === $item['UNITINDEX']; }),
                function ($result1, $set) { return $result1 = array_filter(array_merge_recursive($result1, $set)); }, [ ]
            )
        );
    },
    array_unique(array_column($Array, 'UNITINDEX'))
);

Any help would be great and really appreciated.

You talk about 3 indexes, but you don't use them as indexes at all. Let's use them; how about having a result like this?

First index is GROUPINDEX.

[1] => [
    [GROUPDESC] => Grading Parameters
    [UNITINDEX] => [
        [1] => [
            [ELOCATRIND] => 1, 2
            [ELOCATRDES] => Grading Date: 123 | Grading Date : 123-2
        ]
        [2] => [
            [ELOCATRIND] => 1, 2
            [ELOCATRDES] => Grading Decider: abc | Grading Decider: abc-2
        ]
        [5] => [
            [ELOCATRIND] => 1
            [ELOCATRDES] => 
        ]
    ]
]
[2] => [
        [GROUPDESC] => Genre Codes
        [UNITINDEX] => [
        [1] => [
            [ELOCATRIND] => 1
            [ELOCATRDES] => Grading Date: 2017-02-01
        ]
        [2] => [
            [ELOCATRIND] => 1
            [ELOCATRDES] => Grading Decider: NGR
        ]
    ]
]

The function to get that:

<?php
function parseArr($arr) {
    $return = [];
    foreach($arr as $item) {
        // Check if GROUPINDEX exists
        if(!isset($return[$item['GROUPINDEX']]) {
            $return[$item['GROUPINDEX']] = [
                'GROUPDESC' => $item['GROUPDESC'],
                'UNITINDEX' => []
            ];
        }
        // Check if UNITINDEX exists in this GROUPINDEX
        if(!isset($return[$item['GROUPINDEX']]['UNITINDEX'][$item['UNITINDEX']])) {
            // Create UNITINDEX array
            $return[$item['GROUPINDEX']]['UNITINDEX'][$item['UNITINDEX']] = [
                'ELOCATRIND' => $item['ELOCATRIND'],
                'ELOCATRDES' => $item['ELOCATRDES'] . ': ' . $index['ELOCATRVAL']
            ];
        } else {
            // Update UNITINDEX array, just concat to previous values
            $return[$item['GROUPINDEX']]['UNITINDEX'][$item['UNITINDEX']]['ELOCATRIND'] .= ', ' . $item['ELOCATRIND'];
            $return[$item['GROUPINDEX']]['UNITINDEX'][$item['UNITINDEX']]['ELOCATRDES'] .= ' | ' . $item['ELOCATRDES'] . ': ' . $index['ELOCATRVAL'];
        }
    }
    return $return;
}

This should give you a start.

<?php
$items = [
    [
        'GROUPINDEX' => 1,
        'GROUPDESC' => 'Grading Parameters',
        'UNITINDEX' => 1,
        'ELOCATRIND' => 1,
        'ELOCATRDES' => 'Grading Date',
        'ELOCATRVAL' => '123',
        'CODEDESC' => null
    ], [
        'GROUPINDEX' => 1,
        'GROUPDESC' => 'Grading Parameters',
        'UNITINDEX' => 2,
        'ELOCATRIND' => 1,
        'ELOCATRDES' => 'Grading Decider',
        'ELOCATRVAL' => 'abc',
        'CODEDESC' => null
    ], [
        'GROUPINDEX' => 1,
        'GROUPDESC' => 'Grading Parameters',
        'UNITINDEX' => 5,
        'ELOCATRIND' => 1,
        'ELOCATRDES' => null,
        'ELOCATRVAL' => 'test-DE',
        'CODEDESC' => null
    ], [
        'GROUPINDEX' => 1,
        'GROUPDESC' => 'Grading Parameters',
        'UNITINDEX' => 1,
        'ELOCATRIND' => 2,
        'ELOCATRDES' => 'Grading Date',
        'ELOCATRVAL' => '123-2',
        'CODEDESC' => null
    ], [
        'GROUPINDEX' => 1,
        'GROUPDESC' => 'Grading Parameters',
        'UNITINDEX' => 2,
        'ELOCATRIND' => 2,
        'ELOCATRDES' => 'Grading Decider',
        'ELOCATRVAL' => 'abc-2',
        'CODEDESC' => null
    ], [
        'GROUPINDEX' => 2,
        'GROUPDESC' => 'Genre Codes',
        'UNITINDEX' => 1,
        'ELOCATRIND' => 1,
        'ELOCATRDES' => 'Grading Date',
        'ELOCATRVAL' => '2017-02-01',
        'CODEDESC' => null
    ], [
        'GROUPINDEX' => 2,
        'GROUPDESC' => 'Genre Codes',
        'UNITINDEX' => 2,
        'ELOCATRIND' => 1,
        'ELOCATRDES' => 'Grading Decider',
        'ELOCATRVAL' => 'NGR',
        'CODEDESC' => null
    ]
];

// let create's a dictionary (associative array) keyed on the GROUPINDEX|UNITINDEX
$dict = [];

foreach ($items as $item) {
    $key = $item['GROUPINDEX'] . '|' . $item['UNITINDEX'];
    // check if key does not exist in the dictionary to create a new entry
    if (!isset($dict[$key])) {
        $dict[$key] = [
            'GROUPINDEX' => $item['GROUPINDEX'],
            'GROUPDESC' => $item['GROUPDESC'],
            'UNITINDEX' => $item['UNITINDEX'],
            // for convenience, we'll use arrays here
            'ELOCATRIND' => [],
            'ELOCATRDES' => []
        ];
    }
    // add item to dictionary's entry
    $dict[$key]['ELOCATRIND'][] = $item['ELOCATRIND'];

    // @TODO: ADD SOME CONDITIONAL LOGIC HERE

    $dict[$key]['ELOCATRDES'][] = $item['ELOCATRDES'] . ':' . $item['ELOCATRVAL'];
}

// let's clean up the dictionary now
foreach ($dict as $key => $item) {
    $dict[$key]['ELOCATRIND'] = implode(', ', $item['ELOCATRIND']);
    $dict[$key]['ELOCATRDES'] = implode(' | ', $item['ELOCATRDES']);
}

// sort dictionary by key
ksort($dict);
// remove keys
$dict = array_values($dict);

echo '<pre>' . print_r($dict, true) . '</pre>';
?>

It will output

Array
(
    [0] => Array
        (
            [GROUPINDEX] => 1
            [GROUPDESC] => Grading Parameters
            [UNITINDEX] => 1
            [ELOCATRIND] => 1, 2
            [ELOCATRDES] => Grading Date:123 | Grading Date:123-2
        )

    [1] => Array
        (
            [GROUPINDEX] => 1
            [GROUPDESC] => Grading Parameters
            [UNITINDEX] => 2
            [ELOCATRIND] => 1, 2
            [ELOCATRDES] => Grading Decider:abc | Grading Decider:abc-2
        )

    [2] => Array
        (
            [GROUPINDEX] => 1
            [GROUPDESC] => Grading Parameters
            [UNITINDEX] => 5
            [ELOCATRIND] => 1
            [ELOCATRDES] => :test-DE  
        )

    [3] => Array
        (
            [GROUPINDEX] => 2
            [GROUPDESC] => Genre Codes
            [UNITINDEX] => 1
            [ELOCATRIND] => 1
            [ELOCATRDES] => Grading Date:2017-02-01
        )

    [4] => Array
        (
            [GROUPINDEX] => 2
            [GROUPDESC] => Genre Codes
            [UNITINDEX] => 2
            [ELOCATRIND] => 1
            [ELOCATRDES] => Grading Decider:NGR
        )

)

You'll notice the last three are not the same as your desired result. You would have to add the logic where it says @TODO in comments (because I don't know).

Your code attempts were very close. array_map() would be a good choice if the desired had one value corresponding to each element in the original array. However, because the desired output doesn't have one element for each element in the original array, use array_reduce() with array_filter() inside instead of array_map() . That way, when using array_reduce(), the code can conditionally add the current item to the result array or update the existing item that has the matching UNITINDEX and GROUPINDEX values.

In the code snippet below, also notice that array_keys() is used to get the index of the first found item (if it exists), and array_key_exists() is used to check if the key ELOCATRVAL exists on the found item. In that case, the value is appended to the ELOCATRDES key and the existing value is unset (using unset() ).

$result1 = array_reduce($Array, function($result, $currentItem) {
    $existingItems = array_filter($result, function ($item) use ($currentItem) { 
        return $currentItem['UNITINDEX'] === $item['UNITINDEX'] && $currentItem['GROUPINDEX'] === $item['GROUPINDEX']; 
    });
    if (count($existingItems)) {//matching item found
        $index = array_keys($existingItems)[0];
        if (array_key_exists('ELOCATRVAL', $result[$index])) {
            $result[$index]['ELOCATRDES'] .= ':'.$result[$index]['ELOCATRVAL'];
            unset($result[$index]['ELOCATRVAL']);
        }
        $result[$index]['ELOCATRIND'] .= ', '.$currentItem['ELOCATRIND'];
        $result[$index]['ELOCATRDES'] .= '| '.$currentItem['ELOCATRDES'].':'.$currentItem['ELOCATRVAL'];
    }
    else { //no match - push the item into the array
        $result[] = $currentItem;
    }
    return $result; //return cumulative array after iterating over each item 
}, []); //pass empty array as initial value of $result

See a demonstration of this in this PHP playground example .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM