0

I am trying to assign primary and secondary static key => value into an associative array based on two conditions.

I have an array like this,

$testarray = array(
array(
    array(
        'id' => 'ccdbh-743748',
        'name' => 'test',
        'email' => '[email protected]',
        'newsletter' => 'abc',
        'created_at' => '1546753453'
    ),
    array(
        'id' => 'uisvuiacsiodciosd',
        'name' => 'test',
        'email' => '[email protected]',
        'newsletter' => 'def',
        'created_at' => '1546753453'
    ),
    array(
        'id' => 'sdcisodjcosjdocij',
        'name' => 'test',
        'email' => '[email protected]',
        'newsletter' => 'ghi',
        'created_at' => '1546753453'
    )
),
array(
    array(
        'id' => 'sdcisodjcosjdocij',
        'name' => 'test',
        'email' => '[email protected]',
        'newsletter' => 'abc',
        'created_at' => '1546753453'
    ),
    array(
        'id' => 'ccdbh-743748',
        'name' => 'test',
        'email' => '[email protected]',
        'newsletter' => 'def',
        'created_at' => '1546753453'
    )
),
array(
    array(
        'id' => 'sdcisodjcosjdocij',
        'name' => 'test',
        'email' => '[email protected]'
        'newsletter' => 'abc',
        'created_at' => '1546753453'
    ),
    array(
        'id' => 'sdcisodjcoscisudhiu',
        'name' => 'test',
        'email' => '[email protected]'
        'newsletter' => 'def',
        'created_at' => '1515217453'
    )
)

);

The first condition would be against this ID ccdbh-743748, if we found any matching ID then this must be the primary one, and others will be secondary then. But if there is no ccdbh-743748 found in the array item, then we need to check with the created_at field whichever is older gets the primary value and the remaining will get the secondary attribute.

I have tried this code so far, but I am not sure at this stage how created_at will going to work in this code.

$data = [];
              
foreach( $testarray as $main_items ){
    $newitem=[];
    foreach ($main_items as $sub_item) {
        $p = ($sub_item['id']==='ccdbh-743748') ? 'primary' : 'secondary';
        $sub_item['profile_type']=$p;
        $newitem[]=$sub_item;
    }
    $data[]=$newitem;
}

print_r($data);

At this point, if the array contains ccdbh-743748, it will set primary to that item and others will get secondary value. Do I need to run another loop to check if no array item contains a primary value then does it's mean it should be calculated with the create_at field? Is there a way that we can use array_search with array_column in the existing loop, or is there any better approach to do this?

The final results that I am looking for are like this.

$finalarray = array(
    array(
        array(
            'id' => 'ccdbh-743748',
            'name' => 'test',
            'email' => '[email protected]',
            'newsletter' => 'abc,def,ghi',
            'created_at' => '1546753453',
            'profile_type' => 'primary'
        ),
        array(
            'id' => 'uisvuiacsiodciosd',
            'name' => 'test',
            'email' => '[email protected]',
            'newsletter' => 'def',
            'created_at' => '1546753453',
            'profile_type' => 'secondary'
        ),
        array(
            'id' => 'sdcisodjcosjdocij',
            'name' => 'test',
            'email' => '[email protected]',
            'newsletter' => 'ghi',
            'created_at' => '1546753453',
            'profile_type' => 'secondary'
        )
    ),
    array(
        array(
            'id' => 'sdcisodjcosjdocij',
            'name' => 'test',
            'email' => '[email protected]',
            'newsletter' => 'abc',
            'created_at' => '1546753453',
            'profile_type' => 'secondary'
        ),
        array(
            'id' => 'ccdbh-743748',
            'name' => 'test',
            'email' => '[email protected]',
            'newsletter' => 'abc,def',
            'created_at' => '1546753453',
            'profile_type' => 'primary'
        )
    ),
    array(
        array(
            'id' => 'sdcisodjcosjdocij',
            'name' => 'test',
            'email' => '[email protected]',
            'newsletter' => 'abc',
            'created_at' => '1546753453',
            'profile_type' => 'secondary'
        ),
        array(
            'id' => 'sdcisodjcoscisudhiu',
            'name' => 'test',
            'email' => '[email protected]',
            'newsletter' => 'abc,def',
            'created_at' => '1515217453',
            'profile_type' => 'primary'
        )
    )
);

Thanks

2
  • I do not see the difference between arrays or the logic Commented Jan 6, 2022 at 6:16
  • @GiacomoM The final array contains profile_type in each array item, Commented Jan 6, 2022 at 6:31

2 Answers 2

1

Perhaps this example, made taking into account past wishes for the style of the code and changes in the original question, can help you.

const SPECIAL_KEY = 'ccdbh-743748';
const NEWS_LETTER_DELIMETER = ',';

$total = array_map(
    function($item) {
        $primaryIndex = null;
        $newsLetters = []; 
        array_walk(
            $item,
            function(&$subItem, $index) use (&$item, &$primaryIndex, &$newsLetters) {
                $subItem['profile_type'] = 'secondary';
                $newsLetters = array_merge($newsLetters, explode(NEWS_LETTER_DELIMETER, $subItem['newsletter']));
                if (!is_null($primaryIndex) && $item[$primaryIndex]['id'] === SPECIAL_KEY) return false;
                if (is_null($primaryIndex)
                    || $subItem['id'] === SPECIAL_KEY
                    || intval($item[$primaryIndex]['created_at']) >= intval($subItem['created_at'])) {
                    $primaryIndex = $index;
                }
            }
        );

        $newsLetters = array_unique(array_map('trim', $newsLetters)); // cleaning and normalization of the array
        if (!is_null($primaryIndex)) {
            $item[$primaryIndex]['profile_type'] = 'primary';
            $item[$primaryIndex]['newsletter'] = implode(NEWS_LETTER_DELIMETER, $newsLetters);
        };
        
        return $item;
    },
    $testarray
);

print_r($total);

Working example

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

4 Comments

Isn't there any precise example, like more concise or robust solution for this, Can we not use array_searh with array_column or probably by using array_filter to achieve this ?
@BilalAhmed, I have updated the example to a short version, and also added an example in a different style (which is more comfortable for you).
Thanks for your answer, I have tried your solution and it is working fine. One last thing that I want to fix in this array, I have edited my question and final array. I need to merge or combine all newsletter item values into primary array item with comma separated values. Do you have any preferred solution for this.
@BilalAhmed, I updated the sample code (based on a functional solution) in the response and removed the old code examples from the response.
0

Your nested loop approach is exactly what I would use. The fine detail is in determining if a given row qualifies as the group's primary row.

  1. If there is no cached primary candidate in the group, then use the current row; or
  2. if the current row's id is assigned special significance, use the current row; or
  3. if the current's id is NOT special and the cached row's id is NOT special and the current row's created_at value is less than the cached row's created_at value; then cache the row's index as the best candidate in the group as the primary row.

Beyond that, keep pushing the group's newsletter values into an array while looping.

When the loop finishes, update the winning candidate's data with a "primary" profile_type value and implode all of the group's newsletter values to update the newsletter value.

Code: (Demo)

define('PRIMARY_ID', 'ccdbh-743748');

foreach ($testarray as &$group) {
    $primaryCandidateId = null;
    $newsletters = [];
    foreach ($group as $i => &$row) {
        $row['profile_type'] = 'secondary';
        if (
            $primaryCandidateId === null
            || 
            $row['id'] === PRIMARY_ID
            || (
                !in_array(PRIMARY_ID, [$row['id'], $group[$primaryCandidateId]['id']])
                && $row['created_at'] < $group[$primaryCandidateId]['created_at']
            )
        ) {
            $primaryCandidateId = $i;
        }
        $newsletters[] = $row['newsletter'];
    }
    $group[$primaryCandidateId]['profile_type'] = 'primary';
    $group[$primaryCandidateId]['newsletter'] = implode(',', $newsletters);
}
var_export($testarray);

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.