3

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!

2
  • 1
    What is the logic here? You need to keep the data where time is the highest in the month? Commented Dec 17, 2018 at 19:20
  • @FelippeDuarte yes that is correct. where time is the highest in the month. I just want to keep the last record since it only appends from first day to last day in month. So the last day in month has the "fresh" and "updated" data. Commented Dec 17, 2018 at 19:23

6 Answers 6

5

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

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks @Nick. Worked like charm. So what we are doing is to add the first entry then look for the same $indexKey in $expectedArray, if not match then add, else do nothing. (Sorry new to programming and PHP)
@AliDurrani yes - we check if the $expectedArray entry doesn't exist using isset or if it does exist, we check whether the time in $item is later than the time already in that entry. If either of those cases is true, we set the value in $expectedArray.
Learned something new, to think practical. I was thinking to complex i see now at first. Thank you. And there are alot of great answers, i had to accept this with explaination and demo. Thank you!
1

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));

1 Comment

I will read about spaceship operator, never used it before. Thank you Nigel.
1

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));

Comments

1

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;
    }
}

1 Comment

Thank you @Felippe
1

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.

2 Comments

No it won't. Try it and you will see. It will work with any kind of shuffled array. @FelippeDuarte
Oh.. I see what you mean. Just a sec.
1

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
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.