PHP Remove subarray from main array if specific value range is found - php

Lets say I have the following array:
[9] => Array
(
[0] => Bob Smith
[1] => bobsmith#gmail.com
[2] => Helsinki
[3] => 10
[4] => 34
[5] => 2014-05-12
)
[10] => Array
(
[0] => John Smith
[1] => johnsmith#domain.com
[2] => some values
[3] => 9
[4] => 67
[5] => 2014-05-15
)
[11] => Array
(
[0] => Clarke Kent
[1] => ckent#superman.com
[2] => Crystal
[3] => 9
[4] => 89
[5] => 2014-05-16
)
What if i want to remove a subarray when the date falls outside a specific range. So if i say wanted to find data where the date is between 2014-05-14 and 2014-05-28. Then the (new) array would print the following:
[10] => Array
(
[0] => John Smith
[1] => johnsmith#domain.com
[2] => some values
[3] => 9
[4] => 67
[5] => 2014-05-15
)
[11] => Array
(
[0] => Clarke Kent
[1] => ckent#superman.com
[2] => Crystal
[3] => 9
[4] => 89
[5] => 2014-05-16
)
I thought something like the following:
foreach ($array as $row) {
if($row[5] >= '2014-05-14' && $row[5] <= '2014-05-14') {
// Do Something // e.g. unset subarray?
}
}
OR should i approach it differently and iterate through the array and if a subarray matches my criteria create a new array. The result being an array with subarrays that contain dates that meet my date range. I hope this makes sense, i am trying to find the most efficient way to do this.
Thanks

For the use case described, I would personally use array_filter:
$start_date = DateTime::createFromFormat('Y-m-d', '2014-05-14');
$end_date = DateTime::createFromFormat('Y-m-d', '2014-06-14');
$filtered_array = array_filter($array, function($row) use ($start_date, $end_date) {
$date = DateTime::createFromFormat('Y-m-d', $row[5]);
return $date >= $start_date && $date <= $end_date;
});

Related

Remove duplicate yyyy/mm from array

How I can remove duplicate entries based on Year and Month when my date format is YYYY-MM-DD? I tried removing days, but then I need to add the last day in the array, so my approach was wrong.
My array looks like this:
Array
(
[0] => Array
(
[id] => 9240399
[time] => 2018-01-01
[pages_indexed] => 942
)
[1] => Array
(
[id] => 9240322
[time] => 2018-01-02
[pages_indexed] => 940
)
[2] => Array
(
[id] => 9240344
[time] => 2018-01-03
[pages_indexed] => 947
)
[30] => Array
(
[id] => 9240344
[time] => 2018-01-31
[pages_indexed] => 947
)
[31] => Array
(
[id] => 9240344
[time] => 2018-02-01
[pages_indexed] => 1999
)
[32] => Array
(
[id] => 9240344
[time] => 2018-02-02
[pages_indexed] => 13339
)
Notice that I skipped some entries, so my dates are 2018-01-01, 2018-01-02, etc.
Array_unique would not work here since the day is different.
I tried this: ( $entries['time'] is like ex: 2018-01-01. )
$remove = DATE("Y-m",$entries['time']);
$entriesa = array_unique($remove);
$entries['time'] = $entriesa;
Well... you could loop through your results and index each key as the Year and Month, and then update this index with the row that fits the pattern, meaning you would only have the rows you expect (but you would only have the last reference of them).
Like this:
$expectedArray = [];
foreach ($arrayDuplicated as $item) {
$indexKey = substr($item['time'], 0, 7);
$expectedArray[$indexKey] = $item;
}

Loop through an array and group prices by month, Morris chart

I want to group results by month, to be precise Sum of total prices for each month, but i don't understand how i can divide months, then Sum price for each month.
This is required for morris chart like this
$data2[] = array(
'y' => $month,
'a' => price,
'b' => ''
);
I was using before query to get this results and was a easy way to do it, but now with code is different story.
Any help with explanation of how each segment of code is work will be so nice, so i can avoid problems like this one in future.
I need something like this :
$month = [May, June];
$price = [Sum of all prices for May, Sum of all prices for June];
This is a code :
$monthsArray = array();
// get all dates in array
foreach ($array as $key) {
// convert dates to short format, month-year -> Jun-18
$monthsArray[] = date('M-y', strtotime($key['time']));
}
$months = array();
foreach ($monthsArray as $date) {
$mon = substr($date, 0, 6);
if (!in_array($mon, $months)) array_push($months, $mon);
}
foreach ($months as $m) {
// final array for chart
$data2[] = array('y'=>$m, 'a'=>'', 'b'=>'');
}
$morris = json_encode($data2);
This is array i have
Array
(
[0] => Array
(
[price] => -1835.25
[time] => 2018-05-29 16:53:38
)
[1] => Array
(
[price] => -1743.52
[time] => 2018-05-29 16:53:39
)
[2] => Array
(
[price] => -4445.55
[time] => 2018-05-31 13:21:04
)
[3] => Array
(
[price] => -34647.04
[time] => 2018-05-31 18:29:43
)
[4] => Array
(
[price] => 16888.41
[time] => 2018-06-01 15:05:24
)
[5] => Array
(
[price] => 14369.05
[time] => 2018-06-07 14:44:21
)
[6] => Array
(
[price] => -49579.69
[time] => 2018-06-11 09:14:42
)
[7] => Array
(
[price] => -33300.94
[time] => 2018-06-08 23:50:29
)
[8] => Array
(
[price] => 4413.21
[time] => 2018-06-12 07:15:52
)
[9] => Array
(
[price] => 2724.69
[time] => 2018-06-12 07:15:46
)
[10] => Array
(
[price] => 10224.03
[time] => 2018-06-08 14:00:13
)
[11] => Array
(
[price] => -797.92
[time] => 2018-06-08 13:54:08
)
[12] => Array
(
[price] => -25157.34
[time] => 2018-06-11 11:31:31
)
[13] => Array
(
[price] => 2701.6
[time] => 2018-06-11 14:32:08
)
[14] => Array
(
[price] => 2038.92
[time] => 2018-06-12 07:15:48
)
[15] => Array
(
[price] => -10541.58
[time] => 2018-06-15 10:35:58
)
)
EDIT:
I manage to group months as you can see in updated code and now i am getting only 2 results as i should be, now its just a issue with SUM of data for each month.
This is what i am getting in console
0: {y: "May-18", a: "", b: ""}
1: {y: "Jun-18", a: "", b: ""}

Reorganise array, move indexes to specific locations php

I have an arbitrary number of arrays all containing the same format of data. There are 2 separate for loops looping through two separate SQL query results and adding them to 2 separate arrays.
Once I have all the information in both arrays, I am walking through them and joining them together to make a longer array.
However, as I am writing this array to a csv file, The information needs to be in order in the array so it writes it in order to the csv file. How can I do this?
Array 1
[1] => Array
(
[0] => 2017-07-21 00:00:00
[1] => Foo
[2] => Bar
[3] => 32.63
[4] => 18.36
[5] => 98.46
)
[2] => Array
(
[0] => 2017-07-21 00:00:00
[1] => Foo
[2] => Bar
[3] => 29.74
[4] => 148.68
[5] => 178.42
)
//etc
Array 2
[1] => Array
(
[0] => RTGH707321222
[1] => THIS
[2] => IS
[3] => TEXT
)
[2] => Array
(
[0] => RTGH707321220
[1] => SOME
[2] => WORDS
[3] => HERE
)
//etc
Joining the arrays together
array_walk($array2, function($values, $key) use (&$array1) {
$array1[$key] = array_merge($array1[$key], $values);
} );
After The array Merge - print_r($array1)
[1] => Array
(
[0] => 2017-07-21 00:00:00
[1] => Foo
[2] => Bar
[3] => 32.63
[4] => 18.36
[5] => 98.46
[6] => RTGH707321222
[7] => THIS
[8] => IS
[9] => TEXT
)
[2] => Array
(
[0] => 2017-07-21 00:00:00
[1] => Foo
[2] => Bar
[3] => 29.74
[4] => 148.68
[5] => 178.42
[6] => RTGH707321220
[7] => SOME
[8] => WORDS
[9] => HERE
)
//etc
So this is working fine. However, I would like to move some of these indexes around so that they are in a different order. I have looked into array_splice() but I am not sure if this is the correct method to use.
What I want it to look like
[1] => Array
(
[0] => 2017-07-21 00:00:00
[1] => RTGH707321222
[2] => TEXT
[3] => THIS
[4] => 18.36
[5] => 98.46
[6] => Foo
[7] => 32.63
[8] => IS
[9] => Bar
)
//etc
As you can see, all the information is still the same. The values have just been moved to different indexes. How can I sort the array so that it looks like the above. Can anyone point me in the right direction? Thanks.
This is a simpler method using array_replace() and an ordering array.
No extra loop, no temporary swapping variables.
Code: (Demo)
$array1=[
1=>['2017-07-21 00:00:00','Foo','Bar',32.63,18.36,98.46],
2=>['2017-07-21 00:00:00','Foo','Bar',29.74,148.68,178.42]
];
$array2=[
1=>['RTGH707321222','THIS','IS','TEXT'],
2=>['RTGH707321220','SOME','WORDS','HERE']
];
$order=[0=>'',6=>'',9=>'',7=>'',4=>'',5=>'',1=>'',3=>'',8=>'',2=>''];
array_walk($array2, function($values, $key) use (&$array1,$order) {
$array1[$key] = array_replace($order,array_merge($array1[$key], $values));
});
var_export($array1);
we can use swap technice here like,
<?php
foreach ($arr as $key => $value) {
$swap = $value[1];
$arr[$key][1] = $value[6];
$arr[$key][6] = $swap;
$swap = $value[9];
$arr[$key][9] = $value[2];
$arr[$key][2] = $swap;
$swap = $value[7];
$arr[$key][7] = $value[3];
$arr[$key][3] = $swap;
}
print_r($arr);
?>
$arr is your array.

Pad missing dates in array with value previous day

I have an array generated from a database showing continuous date ranges for products in stock.
The problem I'm having is that when there are missing dates the date range gets broken in 2 parts as shown in a segment of the array below where there are no records for dec 31.
I can tell it is a missing date because the elements [0],[1],[2] in the row before the missing date are equal to the elements [0],[1],[2] in the row after the missing date. Element[3] is the number of days in the [4], [5] date range.
[20] => Array ( [0] => 745637 [1] => 24759 [2] => 6.00 [3] => 23 [4] => 2016-12-08 [5] => 2016-12-30 )
[21] => Array ( [0] => 745637 [1] => 24759 [2] => 6.00 [3] => 2 [4] => 2017-01-01 [5] => 2017-01-02 )
[22] => Array ( [0] => 745637 [1] => 26400 [2] => 5.70 [3] => 23 [4] => 2016-12-08 [5] => 2016-12-30 )
[23] => Array ( [0] => 745637 [1] => 26400 [2] => 5.70 [3] => 2 [4] => 2017-01-01 [5] => 2017-01-02 )
[24] => Array ( [0] => 745637 [1] => 29882 [2] => 7.00 [3] => 23 [4] => 2016-12-08 [5] => 2016-12-30 )
[25] => Array ( [0] => 745637 [1] => 29882 [2] => 7.00 [3] => 2 [4] => 2017-01-01 [5] => 2017-01-02 )
So what I would like to do is merge these rows IF there is only a 1 day gap AND elements [0],[1],[2] in the row before the missing date are equal to the elements [0],[1],[2] after the missing date.
[20] => Array ( [0] => 745637 [1] => 24759 [2] => 6.00 [3] => 23 [4] => 2016-12-08 [5] => 2016-12-30 )
[21] => Array ( [0] => 745637 [1] => 24759 [2] => 6.00 [3] => 2 [4] => 2017-01-01 [5] => 2017-01-02 )
would become:
[20] => Array ( [0] => 745637 [1] => 24759 [2] => 6.00 [3] => 26 [4] => 2016-12-08 [5] => 2017-01-02 )
UPDATE:
This is what I came up with, and it actually works but I'm wondering if there is a cleaner way of doing this
foreach ($data as $rows) {
$current = $rows[0].$rows[1].$rows[2];
$cur_days = $rows[3];
$cur_begin = $rows[4];
$cur_end = $rows[5];
// check if we have a 1-day gap in the date range
$comp_date = date_add(date_create($prev_end), date_interval_create_from_date_string('2 days'));
$comp_date = date_format($comp_date, 'Y-m-d');
if (($current == $previous) && ($comp_date == $cur_begin)) {
$data[$i-1][5] = $cur_end; // update [5] 'end date range'
// calculate new range in days
$date_prev_begin = date_create("$prev_begin");
$date_cur_end = date_create("$cur_end");
$interval = date_diff($date_prev_begin, $date_cur_end);
$new_days=$interval->format('%a');
$data[$i-1][3] = $new_days+1; // update [3] 'days'
unset($data[$i]); // remove row
}
// store current row to use for comparison in next iteration
$previous = $current;
$prev_days = $cur_days;
$prev_begin = $cur_begin;
$prev_end = $cur_end;
$i++;
}
$data=array_values($data); // rearrange array
Not sure if it is more efficient but it contains a few less lines of code:
$new_data = array();
foreach($data as $row) {
$cur_begin = new DateTime($row[4]);
$new_row = $row;
$days = 0;
$last_index = !empty($new_data) ? count($new_data)-1 : -1;
$prev_row = $last_index >= 0 ? $new_data[$last_index] : null;
if(!empty($prev_row)) {
$prev_end = new DateTime($prev_row[5]);
$interval = $prev_end->diff($cur_begin);
$days = $interval->days;
$isdiff = $row[0].$row[1].$row[2] != $prev_row[0].$prev_row[1].$prev_row[2];
}
if(!empty($prev_row) && $days > 0 && !$isdiff) {
$new_data[$last_index][3] += $days+1;
$new_data[$last_index][5] = $row[5];
} else {
$new_data[] = $row;
}
}
var_dump($new_data);
Hope it helps.

Sorting Multidimensional Array by Specific Key

EDIT: For anyone who might come across this post with a similar problem, It was solved by taking konforce's supplied answer and tweaking around a bit with the custom sorting function:
function cmp($a, $b) {
if ($a[5] == $b[5]) {
return ($a[3] < $b[3]) ? -1 :1;
}
return ($a[5] > $b[5]) ? -1 : 1;
}
Notice $a[5] == $b[5] does not return zero. It was changed to check who has the most losses and then sort it in ASC order. I'm sure you can even keep going and add another if-statement in there in-case they have the same losses.
Lastly, all you do is usort($ARRAY, "cmp"); and finito!!!
Original Post
My apologies for coming up with yet another MD Array sorting question but I'm just not getting it. I've searched aplenty
for a solution and although many sites have provided what seemed like a logical answer I still have not been able to figure it out.
My problem is since I'm still learning its been rather difficult for me to grasp the concept of using usort with a custom comparing
function. Atleast, thats what I have seen the most when others have tried to sort MD Arrays.
I'm working on a small project to sharpen up on my php skills. Its a very basic tournament standings script that holds a team's information within an array. I would like to sort the array by most points($array[X][X][5]).
So the array looks something like this:
Array (
[0] => Array (
[0] => Array (
[0] => cooller
[1] => 6
[2] => 6
[3] => 0
[4] => 0
[5] => 18
)
)
[1] => Array (
[0] => Array (
[0] => strenx
[1] => 9
[2] => 5
[3] => 1
[4] => 3
[5] => 18
)
)
[2] => Array (
[0] => Array (
[0] => rapha
[1] => 10
[2] => 8
[3] => 1
[4] => 1
[5] => 25
)
) [3] => Array (
[0] => Array (
[0] => ronald reagan
[1] => 5
[2] => 4
[3] => 0
[4] => 1
[5] => 13
)
)
)
I would like to sort it by most points(cell #5), so it would look like this after sorting:
Array (
[0] => Array (
[0] => Array (
[0] => rapha
[1] => 10
[2] => 8
[3] => 1
[4] => 1
[5] => 25
)
)
[1] => Array (
[0] => Array (
[0] => cooller
[1] => 6
[2] => 6
[3] => 0
[4] => 0
[5] => 18
)
)
[2] => Array (
[0] => Array (
[0] => strenx
[1] => 9
[2] => 5
[3] => 1
[4] => 3
[5] => 18
)
)
[3] => Array (
[0] => Array (
[0] => ronald reagan
[1] => 5
[2] => 4
[3] => 0
[4] => 1
[5] => 13
)
)
)
The player with 25 points would be at the top, followed by 18, 18, and lastly 13. Sorry for my earlier post, was having difficulty wording my question correctly. Thanks in advanced!
I think you want something like this:
usort($standings, function($a, $b) { return $b[0][5] - $a[0][5]; });
Or prior to PHP 5.3:
function cmp($a, $b) { return $b[0][5] - $a[0][5]; }
usort($standings, 'cmp');
When using usort, the $a and $b parameters will be one "layer" into the supplied array. So in your case, an example of $a or $b will be:
[0] => Array (
[0] => cooller
[1] => 6
[2] => 6
[3] => 0
[4] => 0
[5] => 18
)
I'm not sure why you have an extra containing array there, but as you can see, you want to sort based on the [0][5] position.
usort($standings[0][0][5], 'cmp') won't work because the first parameter isn't an array to sort, it's just a single number, the points.

Categories