Reputation: 139
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
Upvotes: 0
Views: 108
Reputation: 47874
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.
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);
Upvotes: 0
Reputation: 2764
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);
Upvotes: 1