PHP: Get array value from other array in loop by condition - php

There are two arrays, one contains lists of playlists, the second contains their covers
Array with covers:
Array
(
[0] => Array
(
[id] => 110
[playlist_id] => 131
[video_key] => Jz4YS6oz
[user] => 20
[date] => 2019-08-09 12:21:40
)
[1] => Array
(
[id] => 109
[playlist_id] => 128
[video_key] => KoLwjBed
[user] => 20
[date] => 2019-08-09 11:37:50
)
)
Array with playlists:
Array
(
[0] => Array
(
[playlist_id] => 132
[playlist_title] => 222
[user] => 20
[date] => 2019-08-09 12:22:09
[cover] =>
[access] => 1
[playlist_videos] => 0
[playlist_featured] => 0
)
[1] => Array
(
[playlist_id] => 131
[playlist_title] => 111
[user] => 20
[date] => 2019-08-09 11:28:47
[cover] =>
[access] => 1
[playlist_videos] => 2
[playlist_featured] => 0
)
[2] => Array
(
[playlist_id] => 128
[playlist_title] => 333
[user] => 20
[date] => 2019-08-08 21:16:55
[cover] =>
[access] => 1
[playlist_videos] => 2
[playlist_featured] => 0
)
)
As can be seen from the code, both arrays contain the key [playlist_id]. It is necessary to somehow iterate the second array, so that the key [cover] gets the value [video_key] from the first array and the keys [playlist_id] match, if there is a playlist in the second array, but there is no cover from the first, then to the key [cover] must must contain null
I tried this varinat,
foreach($playlists as $pls){
foreach($covers as $cover){
if($cover['playlist_id'] == $pls['playlist_id']){
$output['list'][] = array(
'id' => $pls['playlist_id'],
'title' => $pls['playlist_title'],
'videos' => $pls['playlist_videos'],
'cover' => (isset($cover) && $cover['playlist_id'] == $pls['playlist_id']) ? $cover['video_key'] : NULL,
'date' => strtotime($pls['date']) * 1000,
'access' => $pls['access'],
);
}
}
}
Everything seems to be working well, but if the playlist does not have a cover, then the playlist is not displayed. If you remove the check in the second cycle, then in the final array there will be a number of elements equal to the product of the first and second arrays. For example, playlists 3, and covers 2, in the final array there will be 6 elements, some of which will be repeated ...

Using array_walk() you can do it easily. Using $filter scope we checked playlist_id from first array and replaced cover of second array by video_key of first array.
Example:
$filter = array_column($first_array, 'video_key', 'playlist_id');
array_walk($second_array, function (&$val) use ($filter) {
if (isset($filter[$val['playlist_id']])) $val['cover'] = $filter[$val['playlist_id']];
else unset($val['cover']);
});
echo '<pre>', print_r($second_array);
Working demo.

Update your loop. This should work:
foreach($playlists as $pls) {
$NewPlayList = array(
'id' => $pls['playlist_id'],
'title' => $pls['playlist_title'],
'videos' => $pls['playlist_videos'],
'date' => strtotime($pls['date']) * 1000,
'access' => $pls['access'],
'cover' => null
);
foreach($covers as $cover) {
if(isset($cover['playlist_id']) && ($cover['playlist_id'] == $pls['playlist_id'])) {
$NewPlayList['cover'] = $cover['video_key'];
}
}
$output['list'][] = $NewPlayList;
}

return array_map(function($playlist) {
$hasCover = array_filter($covers, function($c) use ($playlist){
return $c['playlist_id'] === $playlist['id'];
});
if (count($hasCover) > 0) {
return [
'id' => $playlist['playlist_id'],
'title' => $hasCover[0]['playlist_title'],
'videos' => $hasCover[0]['playlist_videos'],
'cover' => $hasCover[0]['playlist_videos']['cover'],
'date' => strtotime($hasCover[0]['playlist_videos']['date']) * 1000,
'access' => $hasCover[0]['playlist_videos']['access']
]
} else {
//playlist have no cover
return null;
}
} use ($covers));

Related

Sort associative array by level 4 in php

Here is my sample array, I would like to sort this array based on ShipPrice value which is comes on level 4 of this array, how can we do this in PHP ?
Array
(
[0] => Array
(
[ShippingTypes] =>
[SelectedShipName] =>
[SelectedShipId] =>
[SelectedShipPrice] =>
[MethodName] => UPS
[MethodId] => 6
[SelectedDeliveryDays] =>
[PackageCount] => 1
)
[1] => Array
(
[ShippingTypes] => Array
(
[44] => Array
(
[ShipName] => Local pick up
[ShipPrice] => 12
[DeliveryDays] =>
)
)
[SelectedShipName] => Local pick up
[SelectedShipPrice] => 12
[SelectedShipId] => 44
[MethodName] => Quantity Based
[MethodId] => 3
[SelectedDeliveryDays] =>
)
[2] => Array
(
[ShippingTypes] => Array
(
[1] => Array
(
[ShipName] => KP Office
[ShipPrice] => 10
[DeliveryDays] => 0
)
[2] => Array
(
[ShipName] => Sachet
[ShipPrice] => 15
[DeliveryDays] => 5
)
)
[SelectedShipName] => KP Office
[SelectedShipPrice] => 10
[SelectedShipId] => 1
[MethodName] => Local Pickup From Store
[MethodId] => -1
[SelectedDeliveryDays] => 0
)
)
You can do it using usort and the max ShipPrice you get for all shipping types (supposing that you actually want to check against the max):
usort($results, static function(array $a, array $b) {
return price($a) <=> price($b);
});
function price(array $array): int
{
$shippingTypes = (array) $array['ShippingTypes'];
if (empty($shippingTypes)) {
return 0;
}
return max(array_column($shippingTypes, 'ShipPrice'));
}

Dynamically combine subsets of data with their header row, then group/merge/flatten datasets by a shared column

I have an array of arrays like this which I get from a server's response:
$data = array (
'data1' => array (
0 =>
array (
0 => 'ID',
1 => 'PinCode',
2 => 'Date',
),
1 =>
array (
0 => '101',
1 => '454075',
2 => '2012-03-03',
),
2 =>
array (
0 => '103',
1 => '786075',
2 => '2012-09-05',
),
),
'data2' => array (
0 =>
array (
0 => 'Balance',
1 => 'ID',
),
1 =>
array (
0 => '4533',
1 => '101',
)
),
'data3' => array (
0 =>
array (
0 => 'Active',
1 => 'ID',
),
1 =>
array (
0 => 'Yes',
1 => '101',
),
2 =>
array (
0 => 'No',
1 => '103',
),
),
);
On the above array I perform kind of a left join operation to get the final output below :
Array
(
[0] => Array
(
[ID] => 101
[PinCode] => 454075
[Date] => 2012-03-03
[Balance] => 4533
[Active] => Yes
)
[1] => Array
(
[ID] => 103
[PinCode] => 786075
[Date] => 2012-09-05
[Balance] => 0
[Active] => No
)
)
I will explain how I get the output.
In all the arrays data1 , data2 and data3 the first row is the name of the columns and the remaining rows contain the data for those columns.
Firstly I take the array whose length is maximum in the $data array. Hence from $data I first select data1 array as its length is 3.
Using the following code:
$data1=$data['data1'];
$columns_data1 = $data1[0];
for($i=1;$i<=(count($data1)-1);$i++)
{
$output_data1[] = array_combine($columns_data1,$data1[$i]);
}
echo print_r($output_data1);
I get the output $output_data1 like this :
Array
(
[0] => Array
(
[ID] => 101
[PinCode] => 454075
[Date] => 2012-03-03
)
[1] => Array
(
[ID] => 103
[PinCode] => 786075
[Date] => 2012-09-05
)
)
After this I perform the following operation on data2 and data3 arrays to make their length equal to that of data1 length - 1 i.e excluding the first row which contains column names.
$data2=$data['data2'];
$columns_data2 = $data2[0];
for($i=1;$i<=(count($data1)-1);$i++)
{
if($i<count($data2))
$output_data2[] = array_combine($columns_data2,$data2[$i]);
else
$output_data2[]=array_combine($columns_data2,array('0'=>'0','1'=>'0')); //add the value as 0 to the rows and make the length equal to that of data1. Here I've take index 0 and 1 because first row in data contains two index i.e Balance and ID.
}
echo print_r($output_data2);
This code gives the following output for data2 :
Array
(
[0] => Array
(
[Balance] => 4533
[ID] => 101
)
[1] => Array
(
[Balance] => 0
[ID] => 0
)
)
Similary for data3 :
$data3=$data['data3'];
$columns_data3 = $data3[0];
for($i=1;$i<=(count($data1)-1);$i++)
{
if($i<count($data3))
$output_data3[] = array_combine($columns_data3,$data3[$i]);
else
$output_data3[]=array_combine($columns_data3,array('0'=>'0','1'=>'0'));
}
echo "<pre>"; print_r($output_data3);
gives the output :
Array
(
[0] => Array
(
[Active] => Yes
[ID] => 101
)
[1] => Array
(
[Active] => No
[ID] => 103
)
)
Next I'll combine $output_data1 and $output_data2 :
$left_join_on = array_column($output_data2, "ID");
$first_leftjoin_output = array();
foreach($output_data1 as $values){
$key = array_search($values['ID'], $left_join_on);
if($key ===false){
$key = array_search(0, $left_join_on);
}
unset($output_data2[$key]['ID']);
$first_leftjoin_output[] = array_merge($values,$output_data2[$key]);
}
echo "<pre>"; print_r($first_leftjoin_output);
gives the output :
Array
(
[0] => Array
(
[ID] => 101
[PinCode] => 454075
[Date] => 2012-03-03
[Balance] => 4533
)
[1] => Array
(
[ID] => 103
[PinCode] => 786075
[Date] => 2012-09-05
[Balance] => 0 //added 0 to balance as ID 103 didn't existed in output_data2. just like a left join of sql
)
)
Next I'll do a join on $first_leftjoin_output and $output_data3
$left_join_on_next = array_column($output_data3, "ID");
$second_leftjoin_output = array();
foreach($first_leftjoin_output as $values){
$key = array_search($values['ID'], $left_join_on_next);
if($key ===false){
$key = array_search(0, $left_join_on_next);
}
unset($output_data3[$key]['ID']);
$second_leftjoin_output[] = array_merge($values,$output_data3[$key]);
}
echo "<pre>"; print_r($second_leftjoin_output);
This step gives the final output $second_leftjoin_output which I already mentioned at the beginning of the question.
Array
(
[0] => Array
(
[ID] => 101
[PinCode] => 454075
[Date] => 2012-03-03
[Balance] => 4533
[Active] => Yes
)
[1] => Array
(
[ID] => 103
[PinCode] => 786075
[Date] => 2012-09-05
[Balance] => 0
[Active] => No
)
)
Hence this way I left joined all the three arrays based on matching ID field.
As you can see I'm doing all this in a hard coded way.
If my $data array contains data4 then again I'll have add the code to get $third_leftjoin_output.
I want this process to be dynamic.
I want a dynamic solution such that I just have to pass the $data array and the name of the feild the left join is going to be based on.
Something like this :
$output = left_join_function($data,"ID");
and this function should return the mentioned output. Or any other better solution would be also very helpful.
I'm not able to figure out how this can be done in a neat way.
As you mentioned, you can use a function (https://www.php.net/manual/de/functions.user-defined.php)
function foo($arg_1, $arg_2, /* ..., */ $arg_n)
{
echo "Example function.\n";
return $retval;
}
For you:
function dataJoinStep1($array)
{
// Do something with your array, left join etc.
return $array;
}
You can call the function in a loop (while/for/etc) dataJoinStep1($data)
My recommendation is robust enough to work on a dynamic number of data subsets, but it relies on the fact that all subsets are related by their ID value.
Iterate each group, separate the header data and combine it with subsequent rows within the group.
In the same loop, use first level keys to associate data from previously encountered groups (with the same first level key) and merge related data before pushing it into the result array. When finished iterating, call array_values() to re-index the result array.
Code: (Demo)
var_export(
array_values(
array_reduce(
$data,
function ($result, $group) {
$header = array_shift($group);
$idIndex = array_search('ID', $header);
foreach ($group as $row) {
$result[$row[$idIndex]] = array_merge(
$result[$row[$idIndex]] ?? [],
array_combine($header, $row)
);
}
return $result;
},
[]
)
)
);

Filter a multidimensional array - filter_array (PHP)

How do you filter this multidimensional array with array_filter() based on [channel]?
Array
(
[0] => Array
(
[268a9d2d25fc2b9765c7cd7b8a768d3e] => Array
(
[dj_name] => Emilian
[show_name] => TechnoShow
[channel] => techno
[show_image] => http://www.digitalark.ro/dieselfm/wp-content/uploads/2016/01/avatar.jpg
[time] => 0
[time_end] => 1
[sun1] => 1
[sun2] => 1
[sun3] => 1
[sun4] => 1
[sun5] => 1
)
)
[1] => Array
(
[e13268de7c56db42f8aeab2ab4c607f2] => Array
(
[dj_name] => John Doe
[show_name] => John Doe`s Trance Show
[channel] => trance
[show_image] => http://www.digitalark.ro/dieselfm/wp-content/uploads/2016/01/dummy.jpg
[time] => 11
[time_end] => 11
[mon1] => 1
[mon2] => 1
[tue2] => 1
[mon3] => 1
[fri3] => 1
[mon4] => 1
[mon5] => 1
)
)
)
Results should have only the arrays that have the value "techno", for example:
Array
(
[0] => Array
(
[268a9d2d25fc2b9765c7cd7b8a768d3e] => Array
(
[dj_name] => Emilian
[show_name] => TechnoShow
[channel] => techno
[show_image] => http://www.digitalark.ro/dieselfm/wp-content/uploads/2016/01/avatar.jpg
[time] => 0
[time_end] => 1
[sun1] => 1
[sun2] => 1
[sun3] => 1
[sun4] => 1
[sun5] => 1
)
))
I have tried using:
$data = array_filter($dataraw, function($fs) use ($genre) {return $fs['channel'] == $genre});
EDIT:
$djs = get_posts($args);
foreach ($djs as $dj) {
$temp = maybe_unserialize(get_post_meta($dj->ID, 'show_data',true));
if ($temp) $show_data[] = maybe_unserialize(get_post_meta($dj->ID, 'show_data',true));
}
$datax = array_filter($show_data, function($fs) use ($genre) {
return array_values($fs)[0]['channel'] == $genre;
});
print_r($datax);
I'll assume the parse error in your code was a copy/paste mistake. The problem is that the element passed into the function is a deeper array. Try:
return current($fs)['channel'] === $genre;
Also you might want to use === so the results are as expected.

Swapping elements in an array according to some criteria

I am trying to swap elements in my array according to some criteria.
For example, my array has "blocks" which have to move together, for example move +1 spot in the array.
// bubble sort
foreach ($cleanCard as $key=>$value) {
$cleanCard = handleGroupDirection('down', $value['groupID'], $cleanCard);
}
The $cleanCard array passed as parameter above looks like:
$cleanCard = array(
'0' => array(
'groupID' => 1,
'value' => 'T PHONE'
),
'1' => array
(
'groupID' => 1,
'value' => ''
),
'2' => array
(
'groupID' => 1,
'value' => 'C CELL'
),
'3' => null,
'4' => array
(
'groupID' => 0,
'value' => 'EMAIL'
)
);
As you can see in this array, the element at key #3 is empty, which means that the group should move down 1 spot (even a grouped item that has no value...). The empty key stays in the array.
The resulting array should look like:
Array
(
[0] =>
[1] => Array
(
[groupID] => 1
[value] => T PHONE
)
[2] => Array
(
[groupID] => 1
[value] =>
)
[3] => Array
(
[groupID] => 1
[value] => C CELL
)
[4] => Array
(
[groupID] => 0
[value] => EMAIL
)
)
My code looks like:
function handleGroupDirection($direction, $groupID, $card) {
$groupArr = array_map(function($field) { return $field['groupID']; }, $card);
$groupKeys = array_keys($groupArr, $groupID);
$firstFieldOfGroupIndex = $groupKeys[0];
$lastFieldOfGroupIndex = end($groupKeys);
switch ($direction) {
case 'down':
if ($lastFieldOfGroupIndex+1 >= count($card)) break;
if ($card[$lastFieldOfGroupIndex+1] == null) {
// move each field of the group down, starting
// from the last field in the group
for ($i = count($groupKeys); $i >= 0; $i--) {
$currentCardIndex = $groupKeys[$i];
$card[$currentCardIndex+1] = $card[$currentCardIndex];
}
// make the first field of the group null, the null spot we took is now basically going in front of the group
$card[$firstFieldOfGroupIndex] = null;
}
break;
}
return $card;
}
Haven't had success with this code yet.
Edit:
I get the notices:
NOTICE Undefined offset: 3 on line number 20
$currentCardIndex = $groupKeys[$i];
NOTICE Undefined index: on line number 21
$card[$currentCardIndex+1] = $card[$currentCardIndex];
And the current array I get is:
Array
(
[0] =>
[1] => Array
(
[groupID] => 1
[value] => T PHONE
)
[2] =>
[3] => Array
(
[groupID] => 1
[value] => C CELL
)
[4] => Array
(
[groupID] => 0
[value] => EMAIL
)
)
[2] Shouldn't be empty !

Combine two arrays on key/value and output combined array with PHP

Racking my brain on this, found many examples of similar situations however the solutions don't seem to match up.
I have two arrays being built as the result of SQL queries on different databases.
One is coming through formatted as such:
$data = array([$sku] => array(['LocalSKU'] => $sku,
['Price'] => $msrp,
['Price2'] => $wholesale,
['Price3'] => $distributor,
['Price4'] => $map))
The other array is formatted as such:
$matchme = array([0] => array(['entity_id'] => $entity_id,
['sku'] => $sku,
['type_id'] => $type_id))
Currently, I can get the individual data to match up via:
echo $matchme[0]['sku'];
echo $matchme[0]['entity_id'];
echo $matchme[0]['type_id'];
echo $data[$matchme[0]['sku']]['Price'];
echo $data[$matchme[0]['sku']]['Price2'];
echo $data[$matchme[0]['sku']]['Price3'];
echo $data[$matchme[0]['sku']]['Price4'];
However, when I try and merge the matching rows in both arrays, I get an empty array. The $data array contains 74 unique $sku, and $matchme is the result of checking those $sku's against a database and returning an array with 61 elements. So, the combined array should have 61 elements with matched pricing data based on the $sku.
How I am attempting to build the combined array is below, can anyone point me towards what I am doing wrong?
foreach($matchme as $key){
if(in_array($matchme[$key]['sku'], $data)){
$matched_luggage[$matchme[$key]['sku']][] = array(
'sku' => $matchme[$key]['sku'],
'entity_id' => $matchme[$key]['entity_id'],
'type_id' => $matchme[$key]['type_id'],
'MSRP' => $data[$matchme[$key]['sku']]['Price'],
'Wholesale' => $data[$matchme[$key]['sku']]['Price2'],
'Distributor' => $data[$matchme[$key]['sku']]['Price3'],
'MAP' => $data[$matchme[$key]['sku']]['Price4']
);
}
}
In the above example, evaluate $key as 0, and the value of ['sku'] are matching.
------------------------Edited-------------------------
Per request, here is the result of print_r($data) truncated for space:
Array
(
[12PK-TITANIUM-CR123A] => Array
(
[LocalSKU] => 12PK-TITANIUM-CR123A
[Price] => 11.76
[Price2] => 10.32
[Price3] => 0
[Price4] => 0
)
[AA-CLAMSHELL] => Array
(
[LocalSKU] => AA-CLAMSHELL
[Price] => 0.25
[Price2] => 0
[Price3] => 0
[Price4] => 0
)
[AAA-CLAMSHELL] => Array
(
[LocalSKU] => AAA-CLAMSHELL
[Price] => 0.25
[Price2] => 0
[Price3] => 0
[Price4] => 0
)
[AE-AEL280PI] => Array
(
[LocalSKU] => AE-AEL280PI
[Price] => 0
[Price2] => 0
[Price3] => 0
[Price4] => 0
) )
Per request, here is the result of print_r($matchme) truncated for space:
Array
(
[0] => Array
(
[entity_id] => 693
[sku] => 12PK-TITANIUM-CR123A
[type_id] => simple
)
[1] => Array
(
[entity_id] => 2596
[sku] => AE-AEL480HL
[type_id] => simple
)
[2] => Array
(
[entity_id] => 2597
[sku] => AE-AEL600-T6
[type_id] => simple
)
[3] => Array
(
[entity_id] => 2598
[sku] => AE-AEWL2
[type_id] => simple
) )
Per request, here is the desired result of $matched_luggage:
$matched_luggage = array( [12PK-TITANIUM-CR123A] => array([sku] => 12PK-TITANIUM-CR123A,
[entity_id] => 693,
[type_id] => simple,
[Price] => 11.76,
[Price2] => 10.32,
[Price3] => 0,
[Price4] => 0))
with an additional array per matched sku.
Try this:
foreach ($matchme as $arrProduct) {
if (isset($data[$arrProduct['sku']])) {
$arrMerged[$arrProduct['sku']]=array_merge($arrProduct, $data[$arrProduct['sku']]);
}
}
print_r($arrMerged);
The reason your code doesn't work is here:
if(in_array($matchme[$key]['sku'], $data)) [...]
What in_array() does is tell you whether your needle (in your case the SKU string) exists as a value of array haystack (in your case, $data). You are essentially trying to match a string to an array, rather than another string.
What you really want is just to match the SKU string to the key of $data, for which isset() is probably the simplest approach.
Assuming your first array as $first and second array as $second
foreach ($first as $key => $each) {
foreach ($second as $secondeach) {
if($secondeach['sku'] == $key) {
$first[$key] = array_merge($first[$key], $secondeach);
// unset since you do not want LocalSKU value anymore.
unset($first[$key]['LocalSKU']);
}
}
}
$first is your array you wanted.

Categories