Get averages of values from multidimensional array where date key's match? - php

I have the following multidimensional array,
Array
(
[0] => Array
(
[place] => 1
[date] => 2013-01-01
)
[1] => Array
(
[place] => 2
[date] => 2013-01-02
)
[2] => Array
(
[place] => 3
[date] => 2013-01-03
)
[3] => Array
(
[place] => 10
[date] => 2013-01-01
)
[4] => Array
(
[place] => 8
[date] => 2013-01-02
)
[5] => Array
(
[place] => 5
[date] => 2013-01-03
)
)
How can I get the average place each array where the dates match, so the out put array would look like? The most i've been able to do is loop over the arrays extracting the dates which is pretty easy but finding matches and getting the averages is beyond me. Thanks in advance.
Array
(
[0] => Array
(
[place] => 5.5
[date] => 2013-01-01
)
[1] => Array
(
[place] => 5
[date] => 2013-01-02
)
[2] => Array
(
[place] => 6.5
[date] => 2013-01-03
)
)

$input = array(
array('place' => 1, 'date' => '2013-01-01'),
array('place' => 2, 'date' => '2013-01-02'),
array('place' => 3, 'date' => '2013-01-01'),
);
foreach($input as $pair) $tmp[$pair['date']][] = $pair['place'];
foreach($tmp as $key => $value){
$result[] = array('place' => array_sum($value) / count($value), 'date' => $key);
}
//var_dump($result);
Result:
array (size=2)
0 =>
array (size=2)
'place' => int 2
'date' => string '2013-01-01' (length=10)
1 =>
array (size=2)
'place' => int 2
'date' => string '2013-01-02' (length=10)

You could parse your input array into an array where the keys are the dates and the values are arrays of places for that date:
$tmp = array();
foreach( $input as $entry ) {
$date = $entry["date"];
if( !array_key_exists( $date, $tmp ) ) {
$tmp[$date] = array();
}
$tmp[$date][] = $entry["place"];
}
And now just go over that temporary array, calculate the averages and produce the output format you want:
$averages = array();
foreach( $tmp as $date => $places ) {
$sum = array_sum($places);
$averages[] = array(
"date" => $date,
"place" => $sum / count($places)
);
}
print_r($averages);

Related

Combining duplicate keys in a multidimensional array in PHP [duplicate]

This question already has answers here:
Group subarrays by one column, make comma-separated values from other column within groups
(2 answers)
Closed last month.
here's how it looks in the PHP code:
<?php
$array = array(
array(
'name' => 'filter_amount',
'value' => '100-ml'
),
array(
'name' => 'filter_amount',
'value' => '200-ml'
),
array(
'name' => 'page_size',
'value' => '7'
)
);
print_r($array);
?>
Example of print_r() function output:
Array
(
[0] => Array
(
[name] => filter_amount
[value] => 100-ml
)
[1] => Array
(
[name] => filter_amount
[value] => 200-ml
)
[2] => Array
(
[name] => page_size
[value] => 7
)
)
I need to combine duplicates of filter_amount values from the array.
The values of these duplicates must be commas separated and the result should be the following code:
Array
(
[0] => Array
(
[name] => filter_amount
[value] => 100-ml,200-ml
)
[1] => Array
(
[name] => page_size
[value] => 7
)
[2] => Array
(
[name] => orderby
[value] => rating
)
[3] => Array
(
[name] => paged
[value] => 1
)
)
Since you want value to be concatenated by a comma, you'll have to make a cycle of it
<?php
//Allow me to change this variable name, just to not create confusion
$content = array(
array(
'name' => 'filter_amount',
'value' => '100-ml'
),
array(
'name' => 'filter_amount',
'value' => '200-ml'
),
array(
'name' => 'page_size',
'value' => '7'
)
);
//$content is your initial array
//$outputArray is the final worked-up array
$outputArray = [];
//Let's make a cycle going for every array inside $content
foreach ($content as $innerArray) {
//Does this $innerArray['name'] (filter_ammount) exist in $outputArray in an array
//consisting in key => value where the key is 'name' and equals
//what we look for that is(filter_ammount)?
$key = array_search($innerArray['name'], array_column($outputArray , 'name'));
//If not, let's place this array in the $output array
if ($key === false) {
array_push($outputArray, $innerArray);
} else {
//If exists, then $key is the $key of the $outputArray and let's add to its value
//our current value, that is in our $innerArray, concatenated with a comma
$outputArray[$key]['value'] .= ",". $innerArray['value'];
}
}
//Boom, magic
print_r($outputArray);
//Note: This is going to affect every duplicate it finds, as in:
//If you got 3 arrays with name 'filter_ammount' and 2 arrays with name
//'page_size', it's going to concatenate the filter_ammount and the 'page_size'.
//If you specifically just want filter_ammount,
//replace this -> $key = array_search($innerArray['name'], array_column($outputArray , 'name'));
//with this -> $key = array_search('filter_ammount', array_column($outputArray , 'name'));
?>
References
http://php.net/manual/en/function.array-search.php
http://php.net/manual/en/function.array-column.php
How to combine two items by 2 duplicate columns?
[root#localhost TEST]# php R00.php
Array
(
[0] => Array
(
[0] => S01
[1] => 172.16.20.222
[2] => 10.10.10.100
[3] => 445
)
[1] => Array
(
[0] => S02
[1] => 10.10.10.10
[2] => 192.168.100.100
[3] => 22
)
[2] => Array
(
[0] => S03
[1] => 10.10.10.10
[2] => 192.168.100.100
[3] => 22
)
[3] => Array
(
[0] => S04
[1] => 172.16.20.222
[2] => 10.10.10.100
[3] => 23
)
[4] => Array
(
[0] => S05
[1] => 100.100.100.100
[2] => 192.168.100.100
[3] => 22
)
[5] => Array
(
[0] => S06
[1] => 192.168.200.10
[2] => 192.168.100.100
[3] => 22
)
[6] => Array
(
[0] => S07
[1] => 10.10.10.10
[2] => 192.168.100.100
[3] => 22
)
[7] => Array
(
[0] => S08
[1] => 192.168.100.100
[2] => 10.10.100.106
[3] => 446
)
[8] => Array
(
[0] => S09
[1] => 172.16.20.223
[2] => 10.10.10.108
[3] => 447
)
[9] => Array
(
[0] => S10
[1] => 192.168.100.100
[2] => 10.10.10.109
[3] => 448
)
)
[root#localhost TEST]#
combine 1 or 2 items by 2 column duplicate below is result I need
Array
(
[0] => Array
(
[0] => S01 , S04
[1] => 172.16.20.222
[2] => 10.10.10.100
[3] => 445 , 23
)
[1] => Array
(
[0] => S02 , S03 , S07
[1] => 10.10.10.10
[2] => 192.168.100.100
[3] => 22
)
[3] => Array
(
[0] => S05 , S06
[1] => 100.100.100.100 , 192.168.200.10
[2] => 192.168.100.100
[3] => 22
)
[4] => Array
(
[0] => S08
[1] => 192.168.100.100
[2] => 10.10.100.106
[3] => 446
)
[5] => Array
(
[0] => S09
[1] => 172.16.20.223
[2] => 10.10.10.108
[3] => 447
)
[6] => Array
(
[0] => S10
[1] => 192.168.100.100
[2] => 10.10.10.109
[3] => 448
)
)
Try this:
<?php
$array = array(
array(
'name' => 'filter_amount',
'value' => '100-ml'
),
array(
'name' => 'filter_amount',
'value' => '200-ml'
),
array(
'name' => 'page_size',
'value' => '7'
)
);
$tmp = array();
foreach($array as $val) {
$tmp[$val['name']]['values'][] = $val['value'];
}
foreach($tmp as $k => $v) {
$item = implode(',', array_unique(explode(',', implode(',',$v['values']))));
$newArr[] = array('name' => $k, 'value' => $item);
}
echo '<pre>';
print_r($newArr);
echo '</pre>';
got it with the following crazy mess:
$name = array_column($array, 'name');
$value = array_column($array, 'value');
foreach($name as $nk=>$nv)
foreach($value as $vk=>$vv)
if($nk == $vk)
$a[$nv][] = $vv;
foreach($a as $k=>$v)
$b[$k] = implode(',', $v);
$z = 0;
foreach($b as $k=>$v)
{
$c[$z]['name'] = $k;
$c[$z]['value'] = $v;
$z++;
}
$c is the resulting array
Or using a medley of array functions:
<?php
$array = array(
array(
'name' => 'filter_amount',
'value' => '100-ml'
),
array(
'name' => 'filter_amount',
'value' => '200-ml'
),
array(
'name' => 'page_size',
'value' => '7'
)
);
$names = array_column($array, 'name');
$values = array_column($array, 'value');
$result = [];
foreach (array_unique($names) as $k)
$result[$k] = implode(", ", array_filter($values,
function($v, $indx) use ($names, $k) {
return $names[$indx] == $k;
}, ARRAY_FILTER_USE_BOTH));
print_r($result);
$result2 = [];
foreach ($result as $k=>$v) $result2[] = ['name'=>$k, 'value'=>$v];
print_r($result2);
Results in:
Array
(
[filter_amount] => 100-ml, 200-ml
[page_size] => 7
)
Array
(
[0] => Array
(
[name] => filter_amount
[value] => 100-ml, 200-ml
)
[1] => Array
(
[name] => page_size
[value] => 7
)
)
All of the other answers up to now are using two or more iterating techniques for this task. There only needs to be one loop.
Build an associative output array based on the name values as you iterate. If the associative key isn't set, then save the whole row. If it is set, then just append a comma then the new value data to the stored value element.
Using temporary keys allows isset() to swiftly check for existence. It will always outperform array_search() and in_array() because of how php treats arrays (as hash maps).
Remove the temporary keys when the loop is finished by calling array_values().
Code: (Demo)
$result = [];
foreach ($array as $row) {
if (!isset($result[$row['name']])) {
$result[$row['name']] = $row;
} else {
$result[$row['name']]['value'] .= ',' . $row['value'];
}
}
var_export(array_values($result));
Output:
array (
0 =>
array (
'name' => 'filter_amount',
'value' => '100-ml,200-ml',
),
1 =>
array (
'name' => 'page_size',
'value' => '7',
),
)

Matching array value (PHP Array)

Input post :
$_POST['dateSlot']
$_POST['timeStart']
$_POST['timeEnd']
$_POST['quota']
These input post will resulting the below array.
Array
(
[dateSlot] => Array
(
[0] => 2018-04-05
[1] => 2018-04-05
[2] => 2018-04-05
)
[timeStart] => Array
(
[0] => 11:06 AM
[1] => 10:06 AM
[2] => 9:06 AM
)
[timeEnd] => Array
(
[0] => 11:06 AM
[1] => 9:06 AM
[2] => 7:06 AM
)
[quota] => Array
(
[0] => 12
[1] => 10
[2] => 10
)
)
I'm trying to foreach them to match the index key and form another array with this idea. Not so sure if can get the value I want :
foreach ($_POST['dateSlot'] as $k => $val) {
foreach ($_POST['timeStart'] as $k2 => $val2) {
foreach ($_POST['timeEnd'] as $k3 => $val3) {
foreach ($_POST['quota'] as $k4 => $val4) {
if($k == $k2 && $k == $k3 && $k == $k4){
$timeslots[$k]['date_slot'] = $val;
$timeslots[$k]['time_start'] = $val2;
$timeslots[$k]['time_end'] = $val3;
$timeslots[$k]['event_quota'] = $val4;
}
}
}
}
}
By that foreach, I'm getting the error Illegal string offset for date_slot, time_start, time_end, and event_quota
Based on the rows in the array, my goal is to re-form the array so that they all will be combined together to form 3 rows.
Example :
Array
(
[0] => Array
(
[date_slot] => 2018-04-05
[time_start] => 11:06 AM
[time_end] => 11:06 AM
[event_quota] => 12
)
[1] => Array
(
[date_slot] => 2018-04-05
[time_start] => 10:06 AM
[time_end] => 9:06 AM
[event_quota] => 10
)
[2] => Array
(
[date_slot] => 2018-04-05
[time_start] => 9:06 AM
[time_end] => 7:06 AM
[event_quota] => 10
)
)
Another approach to grouping this kind of data without needing to know the key names in advance.
This works by using the first row's data current( $data ) as the main iterator, then builds an array by combining the outer keys array_keys( $data ) and the inner column value array_column( $data, $column ) with array_combine() which combines two arrays of keys and an array of value to make each row's final array structure keyed by column name.
This is absolutely reliant on each multidimensional array having the same count of elements. As such this is not suitable for forms with checkbox inputs in them. At which point I would suggest using name="row[0][ColumnName]" as your name attribute and negating the need for this array processing.
http://php.net/manual/en/function.array-column.php
http://php.net/manual/en/function.array-combine.php
http://php.net/manual/en/function.array-keys.php
$data = array(
'Column-1'=>array('Row-1a','Row-2a','Row-3a'),
'Column-2'=>array('Row-1b','Row-2b','Row-3b'),
'Column-3'=>array('Row-1c','Row-2c','Row-3c')
);
$array = array();
foreach( array_keys( current( $data ) ) as $column )
{
$array[] = array_combine( array_keys( $data ), array_column( $data, $column ) );
}
print_r( $array );
Produces
Array
(
[0] => Array
(
[Column-1] => Row-1a
[Column-2] => Row-1b
[Column-3] => Row-1c
)
[1] => Array
(
[Column-1] => Row-2a
[Column-2] => Row-2b
[Column-3] => Row-2c
)
[2] => Array
(
[Column-1] => Row-3a
[Column-2] => Row-3b
[Column-3] => Row-3c
)
)
If you know that the element keys in all 4 of those post variables will always correlate to one timeslot element, then I think this will work for you:
foreach ($_POST['dateSlot'] as $key => $value) {
$timeslots[$key] = [
'date_slot' => $_POST['dateSlot'][$key],
'time_start' => $_POST['timeStart'][$key],
'time_end' => $_POST['timeEnd'][$key],
'event_quota' => $_POST['quota'][$key],
];
}
print_r($timeslots);
$dateSlot = $_POST['dateSlot']
$timeStart = $_POST['timeStart']
$timeEnd = $_POST['timeEnd']
$quota = $_POST['quota']
$all = array();
foreach($dateSlot as $key => $date) {
$all[] = array(
"data_slot" => $dateSlot[$key],
"time_start" => $timeStart[$key],
"time_end" => $timeEnd[$key],
"quota" => $quota[$key]
)
}
Input
$array = array(
'dateSlot' => array('2018-04-05','2018-04-05','2018-04-05'),
'timeStart' => array('11:06 AM','10:06 AM','9:06 AM'),
'timeEnd' => array('11:06 AM','9:06 AM','7:06 AM'),
'quota' => array(12,10,10)
);
Solution
$new = array();
for($i=0;$i<count($array['dateSlot']);$i++){
$new[] = array(
'dateSlot' => $array['dateSlot'][$i],
'timeStart' => $array['timeStart'][$i],
'timeEnd' => $array['timeEnd'][$i],
'event_quota' => $array['quota'][$i],
);
}
echo "<pre>";print_r($new);
Output
Array
(
[0] => Array
(
[dateSlot] => 2018-04-05
[timeStart] => 11:06 AM
[timeEnd] => 11:06 AM
[event_quota] => 12
)
[1] => Array
(
[dateSlot] => 2018-04-05
[timeStart] => 10:06 AM
[timeEnd] => 9:06 AM
[event_quota] => 10
)
[2] => Array
(
[dateSlot] => 2018-04-05
[timeStart] => 9:06 AM
[timeEnd] => 7:06 AM
[event_quota] => 10
)
)

PHP: Merge 2 arrays

I've been trying the following for a day now and can't get it to work.
I'm getting information from a paginated source (say 3 pages in this example. So I've got 3 arrays to merge:
Array
(
[status] => Active
[nrEntries] => 6
[entries] => Array
(
[0] => Array
(
[sgname] => Merc
[timeentered] => 2016-02-08 04:30:00
)
[1] => Array
(
[sgname] => bystander
[timeentered] => 2016-03-17 20:55:00
)
)
)
Array
(
[status] => Active
[nrEntries] => 6
[entries] => Array
(
[0] => Array
(
[sgname] => Elvis
[timeentered] => 2016-03-08 04:30:00
)
[1] => Array
(
[sgname] => marcAR
[timeentered] => 2016-03-07 20:55:00
)
)
)
Array
(
[status] => Active
[nrEntries] => 6
[entries] => Array
(
[0] => Array
(
[sgname] => Killer
[timeentered] => 2016-03-09 05:30:00
)
[1] => Array
(
[sgname] => MyName
[timeentered] => 2016-03-05 21:45:00
)
)
)
The result I am looking for is to merge them into 1 array that I can return as a result.
Array
(
[status] => Active
[nrEntries] => 6
[entries] => Array
(
[0] => Array
(
[sgname] => Merc
[timeentered] => 2016-02-08 04:30:00
)
[1] => Array
(
[sgname] => bystander
[timeentered] => 2016-03-17 20:55:00
)
[2] => Array
(
[sgname] => Elvis
[timeentered] => 2016-03-08 04:30:00
)
[3] => Array
(
[sgname] => marcAR
[timeentered] => 2016-03-07 20:55:00
)
[4] => Array
(
[sgname] => Killer
[timeentered] => 2016-03-09 05:30:00
)
[5] => Array
(
[sgname] => MyName
[timeentered] => 2016-03-05 21:45:00
)
)
)
The problem that I'm running into is that with array_merge it won't work because of the identical index numbers of the records.
I tried the following, but that doesn't work either.
<?PHP
// add child array to the end of $result
for ($i=0 ; $i<2; $i++) {
$result['entries'][($page*2)+$i][] = $resultChild['entries'][$i];
}
?>
$a1['entries'] = array_merge_recursive($a1['entries'], $a2['entries'], $a3['entries']);
Try this:
$array1 = array(
'status' => 'Active',
'nrEntries' => 6,
'entries' => array(
array(
'sgname' => 'Merc',
'timeentered' => '2016-02-08 04:30:00'
),
array(
'sgname' => 'bystander',
'timeentered' => '2016-03-17 20:55:00'
)
)
);
$array2 = array(
'status' => 'Active',
'nrEntries' => 6,
'entries' => array(
array(
'sgname' => 'Elvis',
'timeentered' => '2016-03-08 04:30:00'
),
array(
'sgname' => 'marcAR',
'timeentered' => '2016-03-07 20:55:00'
)
)
);
$result = array_merge_recursive($array1, $array2);
$result['status'] = array_unique($result['status'])[0];
$result['nrEntries'] = array_unique($result['nrEntries'])[0];
echo "<pre>";
print_r($result);
echo "</pre>";
This gives the following:
Array
(
[status] => Active
[nrEntries] => 6
[entries] => Array
(
[0] => Array
(
[sgname] => Merc
[timeentered] => 2016-02-08 04:30:00
)
[1] => Array
(
[sgname] => bystander
[timeentered] => 2016-03-17 20:55:00
)
[2] => Array
(
[sgname] => Elvis
[timeentered] => 2016-03-08 04:30:00
)
[3] => Array
(
[sgname] => marcAR
[timeentered] => 2016-03-07 20:55:00
)
)
)
Hope this helps.
array_merge() is not recursive so it will replace your entries array as a whole. There is a function called array_merge_recursive(), but that won't work in your case either, since it will create arrays under status and nrEntries containing the values from all arrays.
What you need to do is to merge the 'big' page arrays, and then merge the entries separately. This could look like this:
// Keep all pages in an array
$pages = [$pageOne, $pageTwo, $pageThree];
// Merge the page arrays
$result = array_merge(...$pages);
// Clear entries as they only contain the data from the last page
$result['entries'] = [];
// Merge entries with the entries of each page separately
foreach ($pages as $page) {
$result['entries'] = array_merge($result['entries'], $page['entries']);
}
This is the simplest example I could think of. I hope it helps you in understanding what is going on, so you can refactor it to suit your needs.
As long as your entries arrays have numeric keys starting from 0, array_merge will append the values instead of replacing them.

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.

Eliminate timestamps within a range from array

This is my array of timestamps. I would like to eliminate values within 30 seconds of each other, only keeping the value if there is not another value within 30 sec. Any help would be greatly appreciated!
Array
(
[99999] => Array
(
[0] => 1356399000
[1] => 1356398971
[2] => 1356399005
[3] => 1356413406
)
[99997] => Array
(
[0] => 1356399002
[1] => 1356399007
[2] => 1356398871
[3] => 1356398876
)
[99996] => Array
(
[0] => 1356399003
[1] => 1356399004
[2] => 1356399008
)
[99995] => Array
(
[0] => 1356399009
)
)
My expected output:
Array
(
[99999] => Array
(
[0] => 1356399000
[1] => 1356398971
[2] => 1356413406
)
[99997] => Array
(
[0] => 1356399002
[1] => 1356398871
)
[99996] => Array
(
[0] => 1356399003
)
[99995] => Array
(
[0] => 1356399009
)
)
Any solutions/advice would be greatly appreciated! Thanks!
Your output is wrong .. because 1356398971 + 30 = 1356399001 which is grater than 1356399000 if i understand you clearly this i what it should look like
$data = array(
99999 => array(
0 => 1356399000,
1 => 1356398971,
2 => 1356399005,
3 => 1356413406,
),
99997 => array(
0 => 1356399002,
1 => 1356399007,
2 => 1356398871,
3 => 1356398876,
),
99996 => array(
0 => 1356399003,
1 => 1356399004,
2 => 1356399008,
),
99995 => array(
0 => 1356399009,
),
);
echo "<pre>";
$data = array_map(function ($values) {
rsort($values);
$ci = new CachingIterator(new ArrayIterator($values));
$values = array();
foreach ( $ci as $ts ) {
if ($ci->hasNext()) {
abs($ci->current() - $ci->getInnerIterator()->current()) > 30 and $values[] = $ts;
} else {
$values[] = $ts;
}
}
sort($values);
return $values;
}, $data);
print_r($data);
Output
Array
(
[99999] => Array
(
[0] => 1356398971
[1] => 1356413406
)
[99997] => Array
(
[0] => 1356398871
[1] => 1356399002
)
[99996] => Array
(
[0] => 1356399003
)
[99995] => Array
(
[0] => 1356399009
)
)

Categories