Multidimensional Array Group By Similar Key/Value Pair - php

I have a multidimensional array that looks like this:
Array (
[0] => Array (
[date] => August
[mozrank] => 2
[domain_authority] => 41
[external_links] => 9
[unique_visitors] => 14
)
[1] => Array (
[date] => August
[post_count] => 70
[comment_count] => 53
[theme] => yes
[plugins] => 3
)
[2] => Array (
[date] => September
[mozrank] => 4
[domain_authority] => 42
[external_links] => 10
[unique_visitors] => 20
)
[3] => Array (
[date] => September
[post_count] => 71
[comment_count] => 56
[theme] => yes
[plugins] => 5
)
)
You'll notice that there are two arrays that have the same key/value pair of August and two arrays that have the same key/value pair of September. However in each case they have different keys associated with them. I'm trying to group each array on the date key where the value is the same and merge the other keys together. For example, the output would be:
Array (
[0] => Array (
[date] => August
[mozrank] => 2
[domain_authority] => 41
[external_links] => 9
[unique_visitors] => 14
[post_count] => 70
[comment_count] => 53
[theme] => yes
[plugins] => 3
)
[1] => Array (
[date] => September
[mozrank] => 4
[domain_authority] => 42
[external_links] => 10
[unique_visitors] => 20
[post_count] => 71
[comment_count] => 56
[theme] => yes
[plugins] => 5
)
)
Any ideas?

First thing that cross my mind:
$merged = array();
foreach ($array as $item)
{
$date = $item['date'];
if (!isset($merged[$date]))
{
$merged[$date] = array();
}
$merged[$date] = array_merge($merged[$date], $item);
}
As result there will be an array where key is a month. If you want standard index (begin from 0) you can always use shuffle().
Result:
array (size=2)
'August' =>
array (size=9)
'date' => string 'August' (length=6)
'mozrank' => int 2
'domain_authority' => int 41
'external_links' => int 9
'unique_visitors' => int 14
'post_count' => int 70
'comment_count' => int 53
'theme' => string 'yes' (length=3)
'plugins' => int 3
'September' =>
array (size=9)
'date' => string 'September' (length=9)
'mozrank' => int 4
'domain_authority' => int 42
'external_links' => int 10
'unique_visitors' => int 20
'post_count' => int 71
'comment_count' => int 56
'theme' => string 'yes' (length=3)
'plugins' => int 5
P.S. I have feeling that it can be done better than this...

Related

array_sum() to values within an array

How can i add array_sum to the string in my loop without making another foreach loop for it? I am trying to combine all of the numbers together instead of having this multi dimensional array and then just have the value and i see that array_sum wont add them up because its inside of an array. any ideas?
$hours_arr = array();
foreach($proj_time as $item){
$hours_arr [$item['project_id']]['item_value'] = $item['item_value'];
$hours_arr [$item['project_id']]['hours'][] = $item['hours'];
}
//output
array (size=3)
4 =>
array (size=2)
'item_value' => string 'Coaching' (length=8)
'hours' =>
array (size=1)
0 => string '999.99' (length=6)
1487 =>
array (size=2)
'item_value' => string 'Standby' (length=7)
'hours' =>
array (size=1)
0 => string '15.00' (length=5)
1488 =>
array (size=2)
'item_value' => string 'Standby' (length=7)
'hours' =>
array (size=4)
0 => string '10.00' (length=5)
1 => string '10.00' (length=5)
2 => string '10.00' (length=5)
3 => string '10.00' (length=5)
I would like my output to be
1488 =>
array (size=2)
'item_value' => string 'Standby' (length=7)
'hours' => string '40.00' (length=5)
edit: added contents of $proj_time
Array
(
[0] => Array
(
[project_id] => 4
[consultant_id] => 51
[engagement_id] => 8
[hours] => 999.99
[item_value] => Coaching
)
[1] => Array
(
[project_id] => 1487
[consultant_id] => 1
[engagement_id] => 1
[hours] => 15.00
[item_value] => Standby
)
[2] => Array
(
[project_id] => 1488
[consultant_id] => 31
[engagement_id] => 7
[hours] => 10.00
[item_value] => Design App RFP
)
[3] => Array
(
[project_id] => 1488
[consultant_id] => 32
[engagement_id] => 41
[hours] => 10.00
[item_value] => Training
)
[4] => Array
(
[project_id] => 1488
[consultant_id] => 55
[engagement_id] => 41
[hours] => 10.00
[item_value] => Training
)
[5] => Array
(
[project_id] => 1488
[consultant_id] => 1
[engagement_id] => 1
[hours] => 10.00
[item_value] => Standby
)
)
Instead of creating array and then applying operation, while creating itself why don't you sum up like this:
DEMO
$hours_arr = array();
foreach($proj_time as $item){
$hours_arr [$item['project_id']]['item_value'] = $item['item_value'];
if(array_key_exists('hours', $hours_arr [$item['project_id']]))
$hours_arr [$item['project_id']]['hours'] += $item['hours'];
else
$hours_arr [$item['project_id']]['hours'] = $item['hours'];
}
Result:
Array
(
[4] => Array
(
[item_value] => Coaching
[hours] => 999.99
)
[1487] => Array
(
[item_value] => Standby
[hours] => 15
)
[1488] => Array
(
[item_value] => Standby
[hours] => 40
)
)
Try this out
<?php
$hours_arr = array();
foreach($proj_time as $item){
if(!isset($hours_arr [$item['project_id']]) || $hours_arr [$item['project_id']]['item_value'] != $item['item_value']) {
$hours_arr [$item['project_id']]['item_value'] = $item['item_value'];
$hours_arr [$item['project_id']]['hours'][] = $item['hours'];
} else {
$hours_arr [$item['project_id']]['hours'][0] += $item['hours'];
}
}

Randomize elements with same value

Hello stackoverflow community. I need help with arrays. It's my weakness. I've got this kind of array:
Array
(
[0] => Array
(
[id] => 7
[slot] => 1
[name] => Apple
[start_date] => 12/16/2015
[end_date] => 03/10/2016
[status] => 1
[pre_exp_email] => 0
)
[1] => Array
(
[id] => 8
[slot] => 1
[name] => Cherry
[start_date] => 12/29/2015
[end_date] => 03/20/2016
[status] => 1
[pre_exp_email] => 0
)
[2] => Array
(
[id] => 5
[slot] => 3
[name] => Bananna
[start_date] => 11/30/2015
[end_date] => 00/00/0000
[status] => 1
[pre_exp_email] => 0
)
[3] => Array
(
[id] => 1
[slot] => 4
[name] => Kiwi
[start_date] => 11/21/2015
[end_date] => 12/21/2016
[status] => 1
[pre_exp_email] => 0
)
)
And my job is to randomize elements which has same [slot], but leave order ascending. For example now it is:
1 Apple 1 Cherry 3 Bannana 4 Kiwi
I need to randomize those elements who has same slot number. So Apple and Cherry would swap positions. How can I do this stuff?
Update : Using shuffle & usort :
shuffle($fruits);
function cmp($a, $b) {
if ($a['slot'] == $b['slot']) {
return 0;
}
return ($a['slot'] < $b['slot']) ? -1 : 1;
}
usort($fruits, "cmp");
Make a new array from the original having slot as keys
$elements = array(
0 => Array
(
'id' => 7,
'slot' => 1
),
1 => Array
(
'id' => 8,
'slot' => 1
),
2 => Array
(
'id' => 9,
'slot' => 1
),
3 => Array
(
'id' => 9,
'slot' => 5
)
);
foreach($elements as $element){
$newArray[$element['slot']][] = $element; //put every element having the same slot
}
$elementSlots = array_keys($newArray); // all slots are stored in elementSlots
$Result = array();
foreach($elementSlots as $slot) {
shuffle($newArray[$slot]); //randomize elements having the same slot
foreach($newArray[$slot] as $element) { //add them to the result array
$Result[$slot][] = $element;//For output 1
//$Result[] = $element; //For output 2
}
}
var_dump($Result);
Output 1:
array (size=2)
1 =>
array (size=3)
0 =>
array (size=2)
'id' => int 7
'slot' => int 1
1 =>
array (size=2)
'id' => int 9
'slot' => int 1
2 =>
array (size=2)
'id' => int 8
'slot' => int 1
5 =>
array (size=1)
0 =>
array (size=2)
'id' => int 9
'slot' => int 5
Output 2:
array (size=4)
0 =>
array (size=2)
'id' => int 7
'slot' => int 1
1 =>
array (size=2)
'id' => int 9
'slot' => int 1
2 =>
array (size=2)
'id' => int 8
'slot' => int 1
3 =>
array (size=2)
'id' => int 9
'slot' => int 5

php join array with same initial value

here's my array
Array
(
[0] => Array
(
[0] => Jan 2010
[1] => 65.75
)
[1] => Array
(
[0] => Jan 2010
[1] => 211.05
)
[2] => Array
(
[0] => Jan 2010
[1] => 582.7
)
[3] => Array
(
[0] => Feb 2010
[1] => 136.3
)
[4] => Array
(
[0] => Feb 2010
[1] => 215.32
)
[5] => Array
(
[0] => Feb 2010
[1] => 413.9
)
[6] => Array
(
[0] => Mar 2010
[1] => 156.35
)
[7] => Array
(
[0] => Mar 2010
[1] => 210.54
)
[8] => Array
(
[0] => Mar 2010
[1] => 585.15
)
[9] => Array
(
[0] => Apr 2010
[1] => 126.1
)
[10] => Array
(
[0] => Apr 2010
[1] => 255.47
)
[11] => Array
(
[0] => Apr 2010
[1] => 329.1
)
[12] => Array
(
[0] => May 2010
[1] => 109
)
[13] => Array
(
[0] => May 2010
[1] => 170
)
[14] => Array
(
[0] => May 2010
[1] => 716.7
)
)
is there any way I can make all arrays with the same value in [0] merge? i want it to be something like this:
Array[0] = (Jan 2010, 65.75, 211.05, 582.7)
Array[1] = (Feb 2010, 136.3, 215.32, 413.9)
and so on...
The closest I can think to do this "simply" (read: taking advantage of native PHP features) is switching to text keys (associative array) for your result. This makes sense from a data modeling perspective as well, since in your sample result arrays you are mixing "key" data and "value" data (e.g. the first value carries the responsibility of being the label for the set == bad). The trick is to use the implicit "push" operator [], which appends a new value to an array.
foreach($sourceArray as $currentSubArray) {
$resultArray[$currentSubArray[0]][] = $currentSubArray[1];
}
Your result will look like this:
Array (
'Jan 2010' => Array (
0 => 65.75,
1 => 211.05,
2 => 582.7,
)
...
)
This is a variant of what #ctrahey suggested, that operates on the input array directly:
foreach($array as $key => &$entry) {
list($month, $value) = $entry;
if (isset($ptr[$month])) {
$ptr[$month][] = $value;
unset($array[$key]);
} else {
$ptr[$month] = &$entry;
}
}
unset($ptr);
Output with your example data:
Array
(
[0] => Array
(
[0] => Jan 2010
[1] => 65.75
[2] => 211.05
[3] => 582.7
)
[3] => Array
(
[0] => Feb 2010
[1] => 136.3
[2] => 215.32
[3] => 413.9
)
[6] => Array
(
[0] => Mar 2010
[1] => 156.35
[2] => 210.54
[3] => 585.15
)
[9] => Array
(
[0] => Apr 2010
[1] => 126.1
[2] => 255.47
[3] => 329.1
)
[12] => Array
(
[0] => May 2010
[1] => 109
[2] => 170
[3] => 716.7
)
)
actionMerge($inputArray);
function actionMerge($inputArray){
$month = array();
$earn = array();
$parentKey = 0;
$callback = function ($value, $key) use (&$month, &$earn, &$parentKey) {
if(!is_array($value)){
if($key == 0){
if(!in_array($value, $month)){
array_push($month, $value);
$earn[$value] = array();
}
$parentKey = $value;
}elseif($key == 1){
array_push($earn[$parentKey], $value);
}
}
};
array_walk_recursive($inputArray, $callback);
echo 'You should use this array';
var_dump($earn); // group money by month, I recommend you to use it
$Array = array();
foreach($month as $m){
$arr = array($m);
$arr = array_merge($arr, $earn[$m]);
array_push($Array, $arr);
}
echo '...Intead of array result what you expect';
var_dump($Array); // your expect result
}
?>
Here is result:
//You should use this array
array (size=5)
'Jan 2010' =>
array (size=3)
0 => float 65.75
1 => float 211.05
2 => float 582.7
'Feb 2010' =>
array (size=3)
0 => float 136.3
1 => float 215.32
2 => float 413.9
'Mar 2010' =>
array (size=3)
0 => float 156.35
1 => float 210.54
2 => float 585.15
'Apr 2010' =>
array (size=3)
0 => float 126.1
1 => float 255.47
2 => float 329.1
'May 2010' =>
array (size=3)
0 => int 109
1 => int 170
2 => float 716.7
//...Intead of array result what you expect
array (size=5)
0 =>
array (size=4)
0 => string 'Jan 2010' (length=8)
1 => float 65.75
2 => float 211.05
3 => float 582.7
1 =>
array (size=4)
0 => string 'Feb 2010' (length=8)
1 => float 136.3
2 => float 215.32
3 => float 413.9
2 =>
array (size=4)
0 => string 'Mar 2010' (length=8)
1 => float 156.35
2 => float 210.54
3 => float 585.15
3 =>
array (size=4)
0 => string 'Apr 2010' (length=8)
1 => float 126.1
2 => float 255.47
3 => float 329.1
4 =>
array (size=4)
0 => string 'May 2010' (length=8)
1 => int 109
2 => int 170
3 => float 716.7
It's quite horrible,but it works...
$resarray=Array(
0 => Array(0 => 'Jan 2010',1 => 65.75),
1=> Array(0 => 'Jan 2010',1 => 211.05),
2 => Array(0 => 'Jan 2010',1 => 582.7),
3 => Array(0 => 'Feb 2010',1 => 136.3),
4 => Array(0 => 'Feb 2010',1 => 215.32),
5 => Array(0 => 'Feb 2010',1 => 413.9),
6 => Array(0 => 'Feb 2010',1 => 156.35),
7 => Array(0 => 'Feb 2010',1 => 210.54),
8 => Array(0 => 'Mar 2010',1 => 585.15),
9 => Array(0 => 'Apr 2010',1 => 126.1),
10 => Array(0 => 'Apr 2010',1 => 255.47),
11 => Array(0 => 'Apr 2010',1 => 329.1),
12 => Array(0 => 'May 2010',1 => 109),
13 => Array(0 => 'May 2010',1 => 170),
14 => Array(0 => 'May 2010',1 => 716.7)
);
$CatArray=array();
$FinArray=array();
$count=count($resarray);
for($i=0;$i<$count;$i++){
$index=array_search($resarray[$i][0],$CatArray);
if(is_numeric($index) && $index>=0)
$FinArray[$index][]=$resarray[$i][1];
else{
$CatArray[]=$resarray[$i][0];
$FinArray[]=array($resarray[$i][0],$resarray[$i][1]);
}
}
unset($CatArray);
unset($resarray);
$count=count($FinArray);
for($i=0;$i<$count;$i++){
$resarray[$i]=implode(',',$FinArray[$i]);
}
Output:
Array
(
[0] => Jan 2010,65.75,211.05,582.7
[1] => Feb 2010,136.3,215.32,413.9,156.35,210.54
[2] => Mar 2010,585.15
[3] => Apr 2010,126.1,255.47,329.1
[4] => May 2010,109,170,716.7
)

PHP: filling arrays in multidimensional one to have the same number of elements

I have the following array with the days of one month grouped by days of the week.
Array
(
[3] => Array
(
[0] => 1
[1] => 8
[2] => 15
[3] => 22
[4] => 29
)
[4] => Array
(
[0] => 2
[1] => 9
[2] => 16
[3] => 23
[4] => 30
)
[5] => Array
(
[0] => 3
[1] => 10
[2] => 17
[3] => 24
[4] => 31
)
[1] => Array
(
[0] => 6
[1] => 13
[2] => 20
[3] => 27
)
[2] => Array
(
[0] => 7
[1] => 14
[2] => 21
[3] => 28
)
)
As you can see all the arrays have five elements but for the last two that have four.
How can I fill the last two arrays so they can also have five elements?
I'd like to fill them with empty values so when I'm printing an html table it'll print nothing after day 31
Thanks a lot
If you really insist on having the fix for the data isntead of having it for the printing as the comment suggested, then you could use array_pad in something like this:
$days = array(....) // that's your original array
foreach($days as $key => $val){
if(count($val)<5)
$days[$key] = array_pad($val, 5, 0);
}
Where array_pad($val, 5, 0); fills the array with 0's till it reaches length 5.
adding values to multid. array using array_push is like so:
array_push ($array[1]['something'], "value");
in your example:
array_push ($array[count($array)][4], 99);
array_push ($array[count($array)-1][4], 99);
You can use array_pad() to do this.
example
$data = array(
array(1, 2, 3, 4, 5),
array(3, 4, 5),
array(4, 9, 10, 11),
array(1, 3, 5, 7, 8)
);
var_dump(array_map(function($val) {
return array_pad($val, 5, '');
}, $data));
outputs
array
0 =>
array
0 => int 1
1 => int 2
2 => int 3
3 => int 4
4 => int 5
1 =>
array
0 => int 3
1 => int 4
2 => int 5
3 => string '' (length=0)
4 => string '' (length=0)
2 =>
array
0 => int 4
1 => int 9
2 => int 10
3 => int 11
4 => string '' (length=0)
3 =>
array
0 => int 1
1 => int 3
2 => int 5
3 => int 7
4 => int 8

Issue with recursive loop and nested multidimensional array

I have here a nested multidimensional array:
Array
(
[merchant] => Array
(
[XML_Serializer_Tag] => Array
(
[id] => 736
[name] => Cadbury Gifts Direct
)
[prod] => Array
(
[XML_Serializer_Tag] => Array
(
[0] => Array
(
[XML_Serializer_Tag] => Array
(
[id] => 88966064
[pre_order] => no
[web_offer] => no
[in_stock] => no
[stock_quantity] => 0
)
[pId] => 608
[isbn] => 0000000000000
[text] => Array
(
[name] => 50% OFF 56g Creme Egg Minis
[desc] => 50% OFF Creme Egg Minis in a 56g bag.
)
[uri] => Array
(
[awTrack] => http://www.awin1.com/pclick.php?p=88966064&a=67702&m=736
[awThumb] => http://images.productserve.com/thumb/736/88966064.jpg
[awImage] => http://images.productserve.com/preview/736/88966064.jpg
[mLink] => http://www.cadburygiftsdirect.co.uk/products/608-50-off-56g-creme-egg-minis.aspx
[mImage] => http://www.cadburygiftsdirect.co.uk/images/thumbs/0001084.png
)
[price] => Array
(
[XML_Serializer_Tag] => Array
(
[curr] => GBP
)
[buynow] => 0.31
[store] => 0.00
[rrp] => 0.00
[delivery] => 0.00
)
[cat] => Array
(
[awCatId] => 437
[awCat] => Chocolate
[mCat] => Full Range
)
[brand] =>
[valFrom] => 0000-00-00
[valTo] => 0000-00-00
[comAmount] => 0.00
)
The segment loop afterwards.
So...
[1] => Array
[2] => Array
[3] => Array
etc...
I need to find the names of the attributes of each array segment.
So I have used this recursive loop:
private function recursive_array($old_array, $new_array = array()) {
foreach ($old_array as $key => $value) {
if (is_array($value) && $key < 1) {
$new_array = $this->recursive_array($value, $new_array);
} else {
if ($key < 1) {
$new_array[] = $key;
}
}
}
return $new_array;
}
This is the output:
array
0 => string 'id' (length=2)
1 => string 'name' (length=4)
2 => string 'id' (length=2)
3 => string 'pre_order' (length=9)
4 => string 'web_offer' (length=9)
5 => string 'in_stock' (length=8)
6 => string 'stock_quantity' (length=14)
7 => string 'pId' (length=3)
8 => string 'isbn' (length=4)
9 => string 'name' (length=4)
10 => string 'desc' (length=4)
11 => string 'awTrack' (length=7)
12 => string 'awThumb' (length=7)
13 => string 'awImage' (length=7)
14 => string 'mLink' (length=5)
15 => string 'mImage' (length=6)
16 => string 'curr' (length=4)
17 => string 'buynow' (length=6)
18 => string 'store' (length=5)
19 => string 'rrp' (length=3)
20 => string 'delivery' (length=8)
21 => string 'awCatId' (length=7)
22 => string 'awCat' (length=5)
23 => string 'mCat' (length=4)
24 => string 'brand' (length=5)
25 => string 'valFrom' (length=7)
26 => string 'valTo' (length=5)
27 => string 'comAmount' (length=9
What it is also picking up is the top nested array:
[XML_Serializer_Tag] => Array
(
[id] => 736
[name] => Cadbury Gifts Direct
)
This is just details for the entire feed not the individual segments.
I need a way of filtering out the top nested array but bear in mind that the details are dynamic so the name of the keys can change from one feed to the next
Maybe this?
$riter = new RecursiveIteratorIterator(New RecursiveArrayIterator($array));
foreach ($riter as $key => $val) {
if ($riter->getDepth() > 1) {
echo "$key => $val\n";
}
}
by default, RecursiveIteratorIterator only visits leaf nodes(the deepest levels down every path). getDepth() can be used to make sure were a minimum depth. I'm not sure if 1 is the correct number, but anyway...
use array_shift to pop off the first element of the array

Categories