Remove previous days in month - PHP Array

Viewed 123

I have an Array that has information about all workdays/jobs that is done in a month. A month can have multiple days that has been a workday. So my Array looks like this (in JSON):

{
"id": 1,
"time": "2018-12-16",
"pages_indexed": 1024
},
{
"id": 2,
"time": "2018-12-12",
"something": 1024
},
{
"id": 3,
"time": "2018-12-09",
"something": 7
},

(....)

{
"id": 12,
"time": "2018-11-12",
"something": 7
},
{
"id": 13,
"time": "2018-11-08",
"something": 7
}

I then tried this:

$expectedArray = [];
foreach ($items as $item) {
    $indexKey = substr($item['time'], 0, 7);
    $expectedArray[$indexKey] = $item;
}
print_r(json_encode($expectedArray));

The problem is that the outcome is that it removes the LAST, and not the first dates and adds it to as the key. This is the output:

"2018-12": {
"id": 123456,
"time": "2018-12-09",
"something": 1029
},
"2018-11": {
"id": 123456,
"time": "2018-11-08",
"something": 1032
},

These are the first days in the list of same month. I would want and expect the output to be:

"2018-12": {
"id": 123456,
"time": "2018-12-16",
"something": 1029
},
"2018-11": {
"id": 123456,
"time": "2018-11-12",
"something": 1032
},

Hope someone could show me how i can proceed. Thank you!

6 Answers

You can just check the times in your loop as you go through it. Then you don't need to worry about whether the input data is sorted.

$expectedArray = [];
foreach ($items as $item) {
    $indexKey = substr($item['time'], 0, 7);
    if (!isset($expectedArray[$indexKey]) || $expectedArray[$indexKey]['time'] < $item['time'])
        $expectedArray[$indexKey] = $item;
}
print_r(json_encode($expectedArray));

Output (for your sample data):

{"2018-12":
     {"id":1,"time":"2018-12-16","pages_indexed":1024},
 "2018-11":
     {"id":12,"time":"2018-11-12","something":7}
}

Demo on 3v4l.org

You could just sort the data be the time field before extracting the data in your main loop. I've used the spaceship operator <=> to compare the dates which is PHP 7+...

usort($items, function ($a, $b) {
    return $a['time'] <=> $b['time'];
});
$expectedArray = [];
foreach ($items as $item) {
    $indexKey = substr($item['time'], 0, 7);
    $expectedArray[$indexKey] = $item;
}
print_r(json_encode($expectedArray));

It is because of your associative array index is same as other so it is replacing the values. You can tweak your code like below. If you want exactly how you shown let me know.

    $expectedArray = [];
foreach ($items as $item) {
    $indexKey = substr($item['time'], 0, 7);
    $expectedArray[$indexKey][] = $item;
}
print_r(json_encode($expectedArray));

Just use a condition:

foreach ($items as $item) {
    $indexKey = substr($item['time'], 0, 7);

    if (!isset($expectedArray[$indexKey]) || ( && ($item['time'] > $expectedArray[$indexKey]['time'])) {
        $expectedArray[$indexKey] = $item;
    }
}

Loop the loop backwards and add it to an associative array with Y-m.
Because of this, this method does not need any kind of logic.

$arr = json_decode($str, true);
$time = array_column($arr, "time"); // for sorting
array_multisort($time, SORT_ASC, $arr); //sort array.

foreach($arr as $sub){
    $result[substr($sub["time"], 0, 7)]= $sub;
}

var_dump($result);

The code will the add the oldest value first and then overwrite with a newer value each time the same month appears.
The end result is the newest values of each month.

Output:

array(2) {
  ["2018-11"]=>
  array(3) {
    ["id"]=>
    int(12)
    ["time"]=>
    string(10) "2018-11-12"
    ["something"]=>
    int(7)
  }
  ["2018-12"]=>
  array(3) {
    ["id"]=>
    int(1)
    ["time"]=>
    string(10) "2018-12-16"
    ["pages_indexed"]=>
    int(1024)
  }
}

https://3v4l.org/RhiO9

I did not include the json_encode but just encode it if that is what you want.

That's because you are duplicating the key for the array and it ends with the last you set for that month. If you want only the first one you should include a flag for every month or you will need to create another array, sort it and then take the first one.

$expectedArray = [];

foreach ($items as $item) {
    $indexKey = substr($item['time'], 0, 7);
    $expectedArray[$indexKey] .= $item.",";
}

$expectedArray_final = [];
foreach($expectedArray as  $expectedIndex=> $expectedValue){
    $ar= explode(",", $expectedValue);
    asort($ar);
    $expectedArray_final[$expectedIndex]=$ar[0];//the first element sorted is the first day of the month
}
Related