i have array object and want get 2 previous and and 2 next array group by specific key.
Array
(
[467] => stdClass Object
(
[id] => 467
[user_id] => 1
)
[468] => stdClass Object
(
[id] => 468
[user_id] => 1
)
[469] => stdClass Object
(
[id] => 469
[user_id] => 1
)
[474] => stdClass Object
(
[id] => 474
[user_id] => 1
)
[475] => stdClass Object
(
[id] => 475
[user_id] => 1
)
[479] => stdClass Object
(
[id] => 479
[user_id] => 1
)
[480] => stdClass Object
(
[id] => 480
[user_id] => 1
)
)
If key define 474 will result:
Previous array group from key 469 and 468
Next array group from key 475 and 479
If don't have previous and next array, i want no result
I try this method, but not working.
$val = 474;
$currentKey = array_search($val, $array);
$before = (isset($array[$currentKey - 2])) ? $array[$currentKey - 2] :
$after = (isset($array[$currentKey + 2])) ? $array[$currentKey + 2] : $array[0];
var_dump($before, $after);
Please help.
What my method will do is, search for the $key value and return its offset in the array. You were using array_search() on the input array's values, so that's where it fell flat.
Then if the offset value is not false, I attempts to slice the 5 desired subarrays from the input array. If it doesn't return 5, then it fails.
The second code will not trigger a failure if the collection of subarrays is less than 5.
Code: (Demo)
$array=[
467=>(object)['id'=>467,'user_id'=>1],
468=>(object)['id'=>468,'user_id'=>1],
469=>(object)['id'=>469,'user_id'=>1],
474=>(object)['id'=>474,'user_id'=>1],
475=>(object)['id'=>475,'user_id'=>1],
479=>(object)['id'=>479,'user_id'=>1],
480=>(object)['id'=>480,'user_id'=>1]
];
$key=480;
// require 5 subarrays or none:
if(($offset=array_search($key,array_keys($array)))<2 || sizeof($result=array_slice($array,$offset-2,5))!=5){
echo "Fail";
}else{
var_export($result);
}
echo "\n---\n";
// allow any number of subarrays up to 5:
if(($offset=array_search($key,array_keys($array)))===false){
echo "Fail";
}else{
// adjust $offset and $length values to handle array "overflow"
if($offset<2){
$length=$offset+3;
}elseif(($diff=sizeof($array)-$offset)<3){
$length=$diff+2;
}else{
$length=5;
}
$offset=max(0,$offset-2);
var_export(array_slice($array,$offset,$length));
}
Output:
Fail
---
array (
0 =>
stdClass::__set_state(array(
'id' => 475,
'user_id' => 1,
)),
1 =>
stdClass::__set_state(array(
'id' => 479,
'user_id' => 1,
)),
2 =>
stdClass::__set_state(array(
'id' => 480,
'user_id' => 1,
)),
)
Here is a visual representation and some more explanation of what the second method is doing:
The following explanation uses a 6-element array to demonstrate the calculations.
I = 'elements labeled by their indices'
S = 'the slice'
T = 'target index'
L = 'length of slice'
I ST ST ST ST ST ST When $target index is:
0 ╗0 ╗ ╗ 0, then $offset=0 and $length=3
1 ║ ║1 ║ ╗ 1, then $offset=0 and $length=4
2 ╝ ║ ║2 ║ ╗ 2, then $offset=0 and $length=5
3 ╝ ║ ║3 ║ ╗ 3, then $offset=1 and $length=5
4 ╝ ║ ║4 ║ 4, then $offset=2 and $length=4
5 ╝ ╝ ╝5 5, then $offset=3 and $length=3
L: 3 4 5 5 4 3
Since your array is not in the sequence, try this one Demo.
$arr = array( 467 => (object) ['id' => 467, 'user_id' => 1],
468 => (object) ['id' => 468, 'user_id' => 1],
469 => (object) ['id' => 469, 'user_id' => 1],
474 => (object) ['id' => 474, 'user_id' => 1],
475 => (object) ['id' => 475, 'user_id' => 1],
479 => (object) ['id' => 479, 'user_id' => 1],
480 => (object) ['id' => 480, 'user_id' => 1],);
$find = 474;
$before2 = $before1 = $next1 = $next2 = array();
$flag = false;
foreach ($arr as $key => $val) {
if($key == $find) {
$flag = true;
}
if(!$flag) {
if(!empty($before1)){
$before2 = $before1;
}
$before1 = $val;
}
if($key != $find) {
if($flag && empty($next2)){
if(!empty($next1)){
$next2 = $next1;
}
$next1 = $val;
}
if(!empty($next2)){
break;
}
}
}
if($flag) {
echo "matching values =>";
var_dump($before2);
var_dump($before1);
var_dump($next1);
var_dump($next2);
} else {
echo "given index not found!";
}
Related
I have an array like below. I need to sort each array on the 2 key.
myarray [
[2020] = [0 => 123, 1 => 234, 2 => 45],
[2021] = [0 => 123, 1 => 34, 2 => 345],
[2019] = [0 => 123, 1 => 134, 2 => 645]
]
So the results would be
[2020] =
45
123
234
[2021] =
34
123
345
[2019] =
123
134
645]
I've tried
array_multisort( array_column($myarray, $myarray[2]), SORT_ASC, $myarray );
and
usort($myarray, array($myarray[2], 'sort_function'));
function sort_function($a, $b)
{
if ($a == $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
}
Neither of the above worked. Would someone please point out my mistake or the correct way to do this?
Here is a better explanation of the problem:
myarray [
[2020] = [0 => 123, 1 => 234, 2 => 357],
[2020] = [0 => 123, 1 => 34, 2 => 157],
[2020] = [0 => 123, 1 => 134, 2 => 257]
]
[2020] =
157
257
357
For your second result, use:
$second_elements = array_column($myarray, 2);
sort($second_elements);
How can I subtract all the columns values? My array is like
Array
(
[0] => Array
(
[id] => 1
[web_traffic] => 442
[form_users] => 131
[date] => 20181004
)
[1] => Array
(
[id] => 2
[web_traffic] => 102
[form_users] => 15
[date] => 20181003
)
[2] => Array
(
[id] => 3
[web_traffic] => 387
[form_users] => 97
[date] => 20181002
)
)
I need to subtract the each column(except date & id) and get the result based on date(Ascending order). For example 20181004 means 4th October 2018. My output should like the below
Array
(
[web_traffic] => -152
[form_users] => -49
)
My code took reference from How to sum all column values in multi-dimensional array?
foreach ($data as $value) {
unset($value[ 'id' ]);
$time = date('Ymd', strtotime($value[ 'date' ]));
if (in_array($time, $dates)) {
$value[ 'date' ] = $time;
foreach ($value as $key => $secondValue) {
if ( !isset($output[ $key ])) {
$output[ $key ] = 0;
}
$output[ $key ] -= $secondValue;
}
}
}
Use PHP array_reduce() and array_column() like this:
$initial_array = array(array('id' => 1,
'web_traffic' => 442,
'form_users' => 131,
'date' => 20181004),
array('id' => 2,
'web_traffic' => 102,
'form_users' => 15,
'date' => 20181003),
array('id' => 3,
'web_traffic' => 387,
'form_users' => 97,
'date' => 20181002));
function sum($carry, $item)
{
$carry -= $item;
return $carry;
}
$web_traffic = array_column($initial_array, "web_traffic");
$form_users = array_column($initial_array, "form_users");
$date = array_column($initial_array, "date");
array_multisort($date, SORT_ASC, $form_users, SORT_DESC, $initial_array);
$result_array = Array(
"web_traffic" => array_reduce(array_column($initial_array, "web_traffic"), "sum",2*$initial_array[0]['web_traffic']),
"form_users" => array_reduce(array_column($initial_array, "form_users"), "sum",2*$initial_array[0]['form_users'])
);
print_r($result_array);
I would first sort the array using usort() in example.
Sorting first, because that can be tricky to substract in 1 loop the oldest datas to the newers one.
Separating intentions provide a cleaner code, easier to maintain.
The dates don't need to be converted into a date. The string is well formatted and can be used as is in a comparison and a sort. "20170101" < "20180101", "20180101" < "20181001" and "20181002" < "20181004"
When done, I'll save the first values as initial values to be used in substract.
Then, loop the sorted array and substract the 'web_traffic' and 'form_users' to the initial values.
$datas = array(array('id' => 1,
'web_traffic' => 442,
'form_users' => 131,
'date' => 20181004),
array('id' => 2,
'web_traffic' => 102,
'form_users' => 15,
'date' => 20181003),
array('id' => 3,
'web_traffic' => 387,
'form_users' => 97,
'date' => 20181002));
//If needed, you can backup the original array, because usort() will modify it.
$backUpDatas = $datas;
//Sort
usort($datas, function ($arr1, $arr2)
{
if (isset($arr1['date']) && isset($arr2['date']))
{
if ($arr1['date'] == $arr2['date'])
return (0);
return (($arr1['id'] > $arr2['id']) ? (-1) : (1));
}
});
//Initial values
$finalValues['web_traffic'] = $datas[0]['web_traffic'];
$finalValues['form_users'] = $datas[0]['form_users'];
//Substract
foreach ($datas as $key => $value)
{
if ($key > 0)
{
if (isset($value['web_traffic']))
$finalValues['web_traffic'] -= $value['web_traffic'];
if (isset($value['form_users']))
$finalValues['form_users'] -= $value['form_users'];
}
}
var_dump($finalValues);
Output :
array (size=2)
'web_traffic' => int -157
'form_users' => int -49
I have get foreach loop in month and total month value count data in array print but only last value print in array
foreach($rawData as $Data)
{
$monthsss = $Data['month_no'];
if($monthsss=='1')
{
$arrayF['jan'] = $Data['month_count'];
}
else
{
$arrayF['jan'] = '0';
}
if($monthsss=='2')
{
$arrayF['feb'] = $Data['month_count'];
}
else
{
$arrayF['feb'] = '0';
}
}
When someone comments and asks Please show input and expected output. this is not done to give you more work, but there are many ways to achieve what you want but many answers can be wrong or require much more code (as with the accepted answer).
Presuming this is your data:
$rawData = [
['month_no' => 1, 'month_count' => 1],
['month_no' => 2, 'month_count' => 1],
['month_no' => 3, 'month_count' => 1],
['month_no' => 4, 'month_count' => 1],
['month_no' => 1, 'month_count' => 2],
['month_no' => 6, 'month_count' => 2],
['month_no' => 7, 'month_count' => 6],
['month_no' => 12, 'month_count' => 4],
];
Do you want just the summed up values?
<?php
$array = [];
foreach ($rawData as $data) {
$m = strtolower(DateTime::createFromFormat('!m', $data['month_no'])->format('M'));
$array[$m] = !isset($array[$m]) ? $data['month_count'] : $array[$m]+$data['month_count'];
}
print_r($array);
https://3v4l.org/vXgCL
Array
(
[jan] => 3
[feb] => 1
[mar] => 1
[apr] => 1
[jun] => 2
[jul] => 6
[dec] => 4
)
Or do you want an array of all the months with the summed up values:
<?php
$array = [];
foreach (range(1, 12) as $month) {
$m = strtolower(DateTime::createFromFormat('!m', $month)->format('M'));
$monthSet = array_filter($rawData, function ($v) use ($month) {
return $v['month_no'] === $month;
});
$array[$m] = 0;
foreach ($monthSet as $data) {
$array[$m] += $data['month_count'];
}
}
print_r($array);
https://3v4l.org/vqnnv
Array
(
[jan] => 3
[feb] => 1
[mar] => 1
[apr] => 1
[may] => 0
[jun] => 2
[jul] => 6
[aug] => 0
[sep] => 0
[oct] => 0
[nov] => 0
[dec] => 4
)
Or perhaps don't even care about the month's strings as your comment suggests.
<?php
$array = [];
foreach ($rawData as $data) {
$m = $data['month_no'];
$array[$m] = !isset($array[$m]) ? $data['month_count'] : $array[$m]+$data['month_count'];
}
print_r($array);
https://3v4l.org/7gKRo
Array
(
[1] => 3
[2] => 1
[3] => 1
[4] => 1
[6] => 2
[7] => 6
[12] => 4
)
Its why we ask..
Please modify your code as follows
foreach($rawData as $Data)
{
$monthsss = $Data['month_no'];
if($monthsss=='1')
{
$arrayF['jan'] = is_null($Data['month_count'])? 0 : $Data['month_count'];
}
if($monthsss=='2')
{
$arrayF['feb'] = is_null($Data['month_count'])? 0 : $Data['month_count'];
}
}
I have a multidimensional array
$array1 = array(
0 => array(34554, 45, 4545454),
1 => array(434534, 35, 345345),
2 => array(43534, 35, 4343445),
3 => array(35534, 34, 342323)
);
Can we find the minimum and maximum value for each value? if we want to find min for first and second column, the other column is max, and the result array is
$array2 = array(
0=>34554,
1=>34,
2=>4545454
);
i've tried this to get min
$result = array(); // save result
array_walk_recursive($ary, function($v, $k) use (&$result) {
if (!isset($result[$k])) $result[$k] = $v;
elseif ($result[$k] > $v) $result[$k] = $v;
});
print_r ($result);
and tried this to get max
$result = array(); // save result
array_walk_recursive($ary, function($v, $k) use (&$result) {
if (!isset($result[$k])) $result[$k] = $v;
elseif ($result[$k] < $v) $result[$k] = $v;
});
print_r ($result);
Thank you.
try below solution:
$array1 = array(
0 => array(34554, 45, 4545454),
1 => array(434534, 35, 345345),
2 => array(43534, 35, 4343445),
3 => array(35534, 34, 342323)
);
//max values
$max_arr = array_map(function ($val) {
return max($val);
}, $array1);
print_r($max_arr);
//min values
$min_arr = array_map(function ($val) {
return min($val);
}, $array1);
print_r($min_arr);
//min and max values
$min_max_arr = array_map(function ($val) {
return array('min' => min($val), 'max' => max($val));
}, $array1);
print_r($min_max_arr);
output:
//max values
Array
(
[0] => 4545454
[1] => 434534
[2] => 4343445
[3] => 342323
)
//min values
Array
(
[0] => 45
[1] => 35
[2] => 35
[3] => 34
)
//min and max values
Array
(
[0] => Array
(
[min] => 45
[max] => 4545454
)
[1] => Array
(
[min] => 35
[max] => 434534
)
[2] => Array
(
[min] => 35
[max] => 4343445
)
[3] => Array
(
[min] => 34
[max] => 342323
)
)
I have added some more element so that you can notice how it works, I have arranged max min as key and value pair, if you will edit your question and show me what you want as output, I will update it.
<?php
$array1 = array(
0 => array(34554, 45, 4545454),
1 => array(434534, 35, 345345),
2 => array(43534, 35, 4343445),
3 => array(9355434, 34, 342323),
4 => array(35534, 34, 342323),
5 => array(8544534, 34, 342323),
6 => array(35534, 34, 342323)
);
foreach($array1 as $arr1){
$max = max($arr1);
$arr[$max] = min($arr1);
}
var_dump($arr);
output
array (size=6)
4545454 => int 45
434534 => int 35
4343445 => int 35
9355434 => int 34
342323 => int 34
8544534 => int 34
Think if I start with an explanation first it will help... I have a competition in which there are 3 winners in each County (The ones with the highest votes).
My current array looks like this:
Array
(
[0] => Array
(
[entryID] => 1
[votes] => 3
[countyID] => 46
)
[1] => Array
(
[entryID] => 4
[votes] => 1
[countyID] => 2
)
[2] => Array
(
[entryID] => 2
[votes] => 0
[countyID] => 46
)
[3] => Array
(
[entryID] => 5
[votes] => 0
[countyID] => 46
)
)
What I need to do here is figure out a way of finding the top 3 highest votes within each of the CountyID's.
Any ideas how I can achieve this?
Thanks,
Scott.
The simplest way to do it is to re-organize your array so the country id is the top level index, and then just write a simple custom function to sort the vote count in descending order... that way the top voted entries are on top.
$entries = array(
array('entryId' => 1, 'votes' => 3, 'countryId' => 46),
array('entryId' => 4, 'votes' => 1, 'countryId' => 2),
array('entryId' => 2, 'votes' => 0, 'countryId' => 46),
array('entryId' => 5, 'votes' => 0, 'countryId' => 46),
);
// Sort votes in descending order (most on top)
function voteSort($a, $b) {
if ($a['votes'] == $b['votes']) {
return 0;
}
return ($a['votes'] < $b['votes']) ? 1 : -1;
}
// Re-organize the array with country as top level
$byCountry = array();
foreach ($entries as $entry) {
$byCountry[$entry['countryId']][] = array(
'entryId' => $entry['entryId'],
'votes' => $entry['votes']
);
}
// For each country, sort by votes
foreach ($byCountry as $index => $country) {
usort($byCountry[$index], 'voteSort');
}
That should work.
You can split the array by unique country IDs in this way:
$entries = array(
array('entryID' => 1, 'votes' => 3, 'countryID' => 46),
array('entryID' => 4, 'votes' => 1, 'countryID' => 2),
array('entryID' => 2, 'votes' => 0, 'countryID' => 46),
array('entryID' => 5, 'votes' => 0, 'countryID' => 46),
);
$entriesByCountry = array();
foreach($entries as $entry) {
if(!array_key_exists($entry->countyID, $entriesByCountry)
$entriesByCountry[$entry->countyID] = array();
$entriesByCountry[$entry->countyID][] = $entry;
}
Than sort each country-array by votes and take the first 3.
The function ksort() will be helpful.
You can sort your array firstly with the rank and second the country. So you will have all of the firsts in every country on the begining of your array, then the seconds, etc.
The function you will pass to ksort will be kind of
function compareVote($a,$b){
if($a['votes'] > $b['votes'])
return 1;
if($a['votes'] == $b['votes']){
if($a['countyID'] > $b['countyID'])
return 1;
if($a['countyID'] == $b['countyID'])
return 0;
return -1;
}
return -1;
}
View the official doc page.