Preserve keys array_splice from another array - php

I am trying to keep keys from an array that i am counting and splicing trough array_splice function. There looks like that i am using wrong method to achieve my goal but i wanted to see if it's possible iwth array_splice
I have 2 arrays:
Task
Employees
Task and Employee (absent) array:
$task_id = ['998', '997', '996', '995', '995', '995', '995', '995', '995', '995', '995', '995'];
$absent = array(
[
'employee' => 'POL',
'absent_from' => '',
'absent_to' => ''
],
[
'employee' => 'FAR',
'absent_from' => '2021-07-12',
'absent_to' => '2021-07-16'
],
[
'employee' => 'FARs',
'absent_from' => '2021-07-12',
'absent_to' => '2021-07-16'
],
[
'employee' => 'FARss',
'absent_from' => '2021-07-12',
'absent_to' => '2021-07-16'
],
[
'employee' => 'FARsss',
'absent_from' => '2021-07-12',
'absent_to' => '2021-07-16'
],
);
What i am trying to achieve:
I want to delegate task_id equal to all employees. So for example i have 10 task and 10 employees i want to divide the tasks to 10 and delegate them to employees. If i have 9 task and 10 employees then everyone will get 2 task but one of them will only get 1 task.
First i add the names in another array from $absent array:
$absent_name = array();
foreach($absent as $key => $name) {
$absent_name[$key] = $name['employee'];
}
Then i try to splice the task_id among the employees (with counting the employees):
$output = array(); // Output / Result (Array)
$input = $task_id; // Tasks (ids)
$num_employees = count($absent_name); // number of employees
for (;$num_employees > 0; $num_employees -= 1) {
$output[] = array_splice($input, 0, ceil(count($input) / $num_employees));
}
print_r($output);
The result is this: (i have tested with more/less employees and task_id and looks like the result array is dividing just like i want it to but i want to keep the names not keys):
Array
(
[0] => Array
(
[0] => 998
[1] => 997
[2] => 996
)
[1] => Array
(
[0] => 995
[1] => 995
[2] => 995
)
[2] => Array
(
[0] => 995
[1] => 995
)
[3] => Array
(
[0] => 995
[1] => 995
)
[4] => Array
(
[0] => 995
[1] => 995
)
)
What i need:
Array
(
[POL] => Array
(
[0] => 998
[1] => 997
[2] => 996
)
[FAR] => Array
(
[0] => 995
[1] => 995
[2] => 995
)
[FARs] => Array
(
[0] => 995
[1] => 995
)
[FARss] => Array
(
[0] => 995
[1] => 995
)
[FARsss] => Array
(
[0] => 995
[1] => 995
)
)
or something simple just so i can add it easly in a DB:
Array
(
[POL] => [998,997,996]
)
[FAR] => [995,995,995]
)
etc......
)
Any idea if i need to change method or can i use array_splice?

I don't think array_splice is going to do any favors for you here, IMO you are working to hard, and should let PHP's array functions do most of the work for you. You can then concentrate on your business logic, which is pretty simple.
Use array_column to easily extract the emplyee IDs from the $absent array.
Use array_map to create and initialize an associative array of arrays, keyed by employee ID.
Loop through the task IDs and use the key, next, and reset functions to advance through the assignment map and wrap around as needed.
// Create an associative array keyed by the employee IDs
$employeeTaskMap = array_flip(array_column($absent, 'employee'));
// Initialize the values to empty arrays
$employeeTaskMap = array_map(fn() => [], $employeeTaskMap);
// Loop through the task IDs
foreach ($task_id as $currTaskId)
{
// Add the task ID to the array at the current pointer in the $employeeTaskMap
$employeeTaskMap[key($employeeTaskMap)][] = $currTaskId;
// Advance the array pointer, reset when we reach the end so we can wrap around
if (next($employeeTaskMap) === false)
{
reset($employeeTaskMap);
}
}
print_r($employeeTaskMap);
Output:
Array
(
[POL] => Array
(
[0] => 998
[1] => 995
[2] => 995
)
[FAR] => Array
(
[0] => 997
[1] => 995
[2] => 995
)
[FARs] => Array
(
[0] => 996
[1] => 995
)
[FARss] => Array
(
[0] => 995
[1] => 995
)
[FARsss] => Array
(
[0] => 995
[1] => 995
)
)
If you really want to use array_splice here for some reason and get your existing code working, use array_combine at the end to use the values of your employee names array as the keys for the output:
$taskBuffer = array(); // Output / Result (Array)
$input = $task_id; // Tasks (ids)
$num_employees = count($absent_name); // number of employees
for (; $num_employees > 0; $num_employees -= 1)
{
$taskBuffer[] = array_splice($input, 0, ceil(count($input) / $num_employees));
}
$output = array_combine($absent_name, $taskBuffer);
This works, but you are having to implement a lot of lower level logic that is unnecessary if you use a simpler, more declarative approach. That introduces more possibility for errors in your code, and makes it difficult for developers who may work with your code (including you six month from now) to understand what you are doing at a glance.

Related

merging array in CI 3

I want to merge two arrays in order to get the data as per my requirement.
I am posting my result, please have a look.
First array:
Array
(
[0] => Array
(
[km_range] => 300
[id] => 2
[car_id] => 14782
)
[1] => Array
(
[km_range] => 100
[id] => 3
[car_id] => 14781
)
[2] => Array
(
[km_range] => 300
[id] => 4
[car_id] => 14783
)
)
Second array:
Array
(
[0] => Array
(
[user_id] => 9c2e00508cb28eeb1023ef774b122e86
[car_id] => 14783
[status] => favourite
)
)
I want to merge the second array into the first one, where the value at key car_id matches the equivalent value; otherwise it will return that field as null.
Required output:
<pre>Array
(
[0] => Array
(
[km_range] => 300
[id] => 2
[car_id] => 14782
)
[1] => Array
(
[km_range] => 100
[id] => 3
[car_id] => 14781
)
[2] => Array
(
[km_range] => 300
[id] => 4
[car_id] => 14783
[fav_status] => favourite
)
)
Since the merge is so specific I would try something like this:
foreach ($array1 as $index => $a1):
foreach ($array2 as $a2):
if ($a1['car_id'] == $a2['car_id']):
if ($a2['status'] == "favourite"):
$array1[$index]['fav_status'] = "favourite";
endif;
endif;
endforeach;
endforeach;
You might be able to optimize the code more but this should be very easy to follow...
Another way to achieve this without using the index syntax is to reference the array elements in the foreach by-reference by prepending the ampersand operator:
foreach($firstArray as &$nestedArray1) {
foreach($secondArray as $nestedArray2) {
if ($nestedArray1['car_id'] == $nestedArray2['car_id']) {
$nestedArray1['fav_status'] = $nestedArray2['status'];
}
}
}
You can see it in action in this Playground example.
Technically you asked about merging the arrays. While the keys would be different between the input arrays and the desired output (i.e. "status" vs "fav_status"), array_merge() can be used to merge the arrays.
if ($nestedArray1['car_id'] == $nestedArray2['car_id']) {
$nestedArray1 = array_merge($nestedArray1, $nestedArray2);
}
Playground example.
Additionally the union operators (i.e. +, +=) can be used.
If you want to append array elements from the second array to the first array while not overwriting the elements from the first array and not re-indexing, use the + array union operator1
if ($nestedArray1['car_id'] == $nestedArray2['car_id']) {
$nestedArray1 += nestedArray1;
}
Playground example.
1http://php.net/manual/en/function.array-merge.php#example-5587

PHP Nested foreach with Key

I have been trying to work this out for two days now and am hitting a brick wall. I have a skyscanner array that has flight itineraries where I have the flight
Leg - being Itineraries -> OutboundLegId -
and also the legs which shows the flight number - being
Legs -> FlightNumbers -> FlightNumber.
What I am trying to achieve is to display the Itinerary and then join the Flight Number on to that. But no matter what I try I cannot get this to work. I have read all about Keys on here and tried loads of examples but am coming up with nothing. Can someone point me in the right direction please?
Example arrays below
[Itineraries] => Array
(
[0] => Array
(
[OutboundLegId] => 13542-1610140610-29-0-13445-1610141240
[InboundLegId] => 13445-1610211340-29-0-13542-1610211640
[PricingOptions] => Array
(
[0] => Array
(
[Agents] => Array
(
[0] => 2174187
)
[QuoteAgeInMinutes] => 31
[Price] => 200.98
[DeeplinkUrl] => http://partners.api.skyscanner.net/apiservices/deeplink/v2?_cje=5JlLCgyPUKY0hT8T0Ybh6dL0Xf0htAiHTFX7RU79eeI3XvrsxvEqP1QUJAoHiHRd&url=http%3a%2f%2fwww.apideeplink.com%2ftransport_deeplink%2f4.0%2fUK%2fen-gb%2fGBP%2fcook%2f2%2f13542.13445.2016-10-14%2c13445.13542.2016-10-21%2fair%2fairli%2fflights%3fitinerary%3dflight%7c-32294%7c1152%7c13542%7c2016-10-14T06%3a10%7c13445%7c2016-10-14T12%3a40%2cflight%7c-32294%7c1153%7c13445%7c2016-10-21T13%3a40%7c13542%7c2016-10-21T16%3a40%26carriers%3d-32294%26passengers%3d1%2c0%2c0%26channel%3ddataapi%26cabin_class%3deconomy%26facilitated%3dfalse%26ticket_price%3d200.98%26is_npt%3dfalse%26is_multipart%3dfalse%26client_id%3dskyscanner_b2b%26request_id%3d3bc96bda-fd7c-403a-b841-2ccc3c26071d%26commercial_filters%3dfalse%26q_datetime_utc%3d2016-09-29T08%3a18%3a27
)
[Legs] => Array
(
[0] => Array
(
[Id] => 13542-1610140610-29-0-13445-1610141240
[SegmentIds] => Array
(
[0] => 1
)
[OriginStation] => 13542
[DestinationStation] => 13445
[Departure] => 2016-10-14T06:10:00
[Arrival] => 2016-10-14T12:40:00
[Duration] => 270
[JourneyMode] => Flight
[Stops] => Array
(
)
[Carriers] => Array
(
[0] => 105
)
[OperatingCarriers] => Array
(
[0] => 105
)
[Directionality] => Outbound
[FlightNumbers] => Array
(
[0] => Array
(
[FlightNumber] => 1152
[CarrierId] => 105
)
)
)
Assuming this is one big array and its called $data you can nest a couple of foreach loops.
I use foreach loops as I assume there are cases where this data structure get more complex than the one you show
foreach ( $data['Itineraries'] as $itin ) {
foreach ( $data['Legs'] as $legs) {
if ($legs['Id'] == $itin['OutboundLegId']) {
// we matched the itinerary with a leg
echo $legs['OutboundLegId'] . ' ' . $legs['FlightNumbers'][0]['FlightNumber'];
}
}
}
Use it as draft. Can't perform function without feedback.
Put proper arrays instead of {YOUR-ARRAY-WITH-LEGS} and {YOUR-ARRAY-WITH-ITINERARIES}
$sortedLegs = array_column('Id', {YOUR-ARRAY-WITH-LEGS});
$joinedArray = array_map(function($itinerary) use($sortedLegs){
if(array_key_exists($itinerary['OutboundLegId'],$sortedLegs)) {
$itinerary['legs'] = $sortedLegs[$itinerary['OutboundLegId']];
}
return $itinerary;
},{YOUR-ARRAY-WITH-ITINERARIES});

Searching 4 level deep array in PHP

Good evening,
I found myself in a bit of a pickle here, with an overcomplicated (i think) $_SESSION array that is set right after a user logs in and contains the info of all User Groups where that user is on, and also this user type of permissions on Group of Devices where that specific user group is allowed.
Here's the deal with irrelevant info ommited:
Array
(
... other stuff ...
[user_groups] => Array
(
[0] => Array
(
[GroupUsersId] => 4
[GroupUsersName] => XXXX
[idUserType] => 2
[NameTypeUser] => Manager
[DevicesAllowed] => Array
(
[GroupDevicesId] => Array
(
[0] => 2
)
[DevicesOnGroup] => Array
(
[0] => 22,24,16
)
)
)
[1] => Array
(
[GroupUsersId] => 5
[GroupUsersName] => YYYY
[idUserType] => 3
[NameTypeUser] => Guest
[DevicesAllowed] => Array
(
)
)
[2] => Array
(
[GroupUsersId] => 1
[GroupUsersName] => ZZZ
[idUserType] => 1
[NameTypeUser] => Admin
[DevicesAllowed] => Array
(
[GroupDevicesId] => Array
(
[0] => 2
)
[DevicesOnGroup] => Array
(
[0] => 1,5,13,12,17,21,22,24,16
)
)
)
)
... more stuff ...
I need to find out what kind of permissions, if any, does the guy has if trying to browse the device with, let's say, DeviceId = 5. If that particular Id is not on any of the arrays, the user isn't even allowed to see it...
I already tryed to change the code in this question How to search by key=>value in a multidimensional array in PHP, but I guess I'm missing some kind of iteration over the arrays.
Any help?
Cheers and thanks in advance.
Edit: $_SESSION can be changed if needed...
(Updated as per comment below) I might be completely missing your point, but would not just iterative processing of your array help?
$user_groups = array(
0 => array(
'GroupUsersName' => 'XXX',
'NameTypeUser' => 'Admin',
'idUserType' => 3,
'DevicesAllowed' => array(
'DevicesOnGroup' => array(
1, 2, 3
)
)
),
1 => array(
'GroupUsersName' => 'YYY',
'NameTypeUser' => 'ReadOnly',
'idUserType' => 1,
'DevicesAllowed' => array(
'DevicesOnGroup' => array(
3, 4, 5
)
)
)
);
$device = 3;
$right = 0;
foreach ($user_groups as $group) {
if (array_key_exists('DevicesOnGroup', $group['DevicesAllowed'])) {
if (in_array($device, $group['DevicesAllowed']['DevicesOnGroup'])) {
if ($group['idUserType'] > $right) {
$right = $group['idUserType'];
}
}
}
}
print_r($right);
Outputs:
3
If you would ask for device which is in no group, it would return 0 (i.e. no access).
iterate the array like this
$guysDeviceId ;
$bGuyMayPass = false;
foreach($_SESSION["user_group"] as $userGroup ){
if(!isset($userGroup[DevicesAllowed]) || !isset($userGroup[DevicesAllowed][DevicesOnGroup])){
continue;
}
if(in_array($userGroup[DevicesAllowed][DevicesOnGroup], $guysDeviceId ){
$bGuyMayPass= true;
}
}
if($bGuyMayPass){
//login, whatever
}

Array_Unique filtering

I have an multidimensional array:
Array
(
[0] => Array
(
[Id] => 1
[MTime_Id] => 1
[MName] => Breakfast
[DName] => Other Cereals
[IName] =>
[Date] => 2013-02-05
)
[1] => Array
(
[Id] => 1
[MTime_Id] => 1
[MName] => Breakfast
[DName] => Porridge
[IName] => Oats,Milk,Sugar
[Date] => 2013-02-06
)
[2] => Array
(
[Id] => 1
[MTime_Id] => 1
[MName] => Breakfast
[DName] => Porridge
[IName] => Oats,Milk,Sugar,Oats,Milk,Sugar
[Date] => 2013-02-05
)
)
And I am trying to use array unique to filter this
[IName] => Oats,Milk,Sugar,Oats,Milk,Sugar
I am having no luck. How can I filter the duplicates?
Cheers.
If you filter input and therefore don't have extra spaces in IName field, you can use something as simple as this for filtering:
$array[2]['IName'] = implode(',', array_unique(explode(',', $array[2]['IName'])));
The problem is that you habe in array two Oats,Milk,Sugar as element of IName, in array three you have Oats,Milk,Sugar,Oats,Milk,Sugar. This is not the same!
"Oats,Milk,Sugar"=="Oats,Milk,Sugar,Oats,Milk,Sugar" (or "Oats,Milk,Sugar".equals("Oats,Milk,Sugar,Oats,Milk,Sugar")) is false.
If you want to have it unique you have to explode the single results and then do a unique on it or you have to store the single values in seperate fields...
BTW: Here is a link how to remove duplicates from a multi dimensional array How to remove duplicate values from a multi-dimensional array in PHP
I am not sure if a function exists for that, here is a simple solution,
you can loop the array, and get the result of each value, then explode result, and insert it into an array.
then use the array_unique function.
try this:
$result = array();
foreach($arrays as $array)
{
$tmp = $array['IName'];
$tmp2 = explode(',',$tmp);
foreach ($tmp2 as $t)
{
$result[]=$t;
}
}
$array_unique = array_unique($result);

Merge arrays together based on different values

I am having trouble thinking of the logic with the following problem:
I have the following array (has been snipped, as its much larger)
Array
(
[0] => Array
(
[code] => LAD001
[whqc] => GEN
[stocktag] => NONE
[qty] => 54
)
[1] => Array
(
[code] => LAD001
[whqc] => GEN
[stocktag] => NONE
[qty] => 6
)
[2] => Array
(
[code] => LAD004
[whqc] => HOLD
[stocktag] => NONE
[qty] => 6
)
)
I basically need to comebine all the keys in this array so that where the code, whqc and stocktag are the same, add the qty values together. With the example below, I need to end up with this:
Array
(
[0] => Array
(
[code] => LAD001
[whqc] => GEN
[stocktag] => NONE
[qty] => 60
)
[1] => Array
(
[code] => LAD004
[whqc] => HOLD
[stocktag] => NONE
[qty] => 6
)
)
As the first and second keys of the array had the same code, whqc and stocktag, the qty's have been added together into the one key.
Any ideas?
I would suggest combining the group values in to a hash, storing the full array under the hash as a key and if you have a duplicate, add the quantity, then do array_values() to pull the results.
$aggregated = array();
foreach ($records as $cRec) {
// The separator | has been used, if that appears in the tags, change it
$cKey = md5($cRec['code'] . '|' . $cRec['whqc'] . '|' . $cRec['stocktag']);
if (array_key_exists($cKey, $aggregated)) {
$aggregated[$cKey]['qty'] += $cRec['qty'];
} else {
$aggregated[$cKey] = $cRec;
}
}
// Reset the keys to numerics
$aggregated = array_values($aggregated);
I would try something like:
$output = array();
foreach($array as $details){
//make distinct key
$key = $details['code'].'_'.$details['whqc'];
if(!isset($output[$key])){
$output[$key] = $details;
}else{
$output[$key]['qty'] += $details['qty'];
$output[$key]['stocktag'] = $details['stocktag'];
}
}
$output = array_values($output);
print_r($output);
update: Orbling was first ;-)

Categories