2

I have N arrays. with n grade_items subarrays. just like this.

array:2 [
  0 => array:10 [
    "id" => 9
    "course_id" => 6
    "semester_id" => 2
    "name" => "Assignment"
    "total_score" => 10
    "grade_items" => array:1 [
      0 => array:7 [
        "id" => 5
        "gradelist_id" => 9
        "student_course_id" => 11
        "score" => 8
        "created_at" => "2020-04-21T03:31:20.000000Z"
        "updated_at" => "2020-04-21T20:04:10.000000Z"
      ]
    ]
  ]
  1 => array:10 [
    "id" => 10
    "course_id" => 6
    "semester_id" => 2
    "name" => "Pop Quiz"
    "total_score" => 20
    "grade_items" => array:1 [
      0 => array:7 [
        "id" => 6
        "gradelist_id" => 10
        "student_course_id" => 11
        "score" => null
        "created_at" => "2020-04-22T00:11:17.000000Z"
        "updated_at" => "2020-04-22T00:11:17.000000Z"
      ]
    ]
  ]
]

I am trying to add each grade_item subarray from each array where the student_course_id is the same. Where there is only one grade_item and no other one with the same student_course_id, then it returns just that one value instead of a sum.

I have gone through this thread

But it just messed up the logic in my head further. I've been at this for weeks.

When I add the scores from each grade_item, i want to put that value into another model say "result_model" that would look like:

result_item [
    "id" => 1,
    "student_course_id" => 11,
    "score" => 15 //total of grade_items from all arrays where the student_course_id's were the same
];

Help!

mickmackusa
  • 43,625
  • 12
  • 83
  • 136
Pogo
  • 43
  • 9
  • where does the id come from the result model - i understand student_course_id and score (sum of same course ids ) but didn't get id – Ersoy Apr 23 '20 at 00:19
  • It's automatically generated when I create a new instance of the model. I just gave a structure to what it should look like after the model is saved. – Pogo Apr 23 '20 at 00:23
  • Like when it checks the first grade_item in the first array, It would search through other arrays(not that sub array), for other grade_items with the same student_course_id and add the scores together. Then create a new result_item with the student_course_id and the computed score. – Pogo Apr 23 '20 at 00:29
  • asking to clarify, at the end of the day; you want the sum of scores which are grouped by student_course_id right ? – Ersoy Apr 23 '20 at 00:31
  • yeah, exactly. but across the arrays not just within the subarrays. – Pogo Apr 23 '20 at 00:34
  • yeah, exactly. but across the arrays not just within the subarrays. By the way, the student_course_id's within a subarray are always unique. There can't be two items with same student_course_id. I hope this gives it some clarity – Pogo Apr 23 '20 at 00:34

4 Answers4

2

So basically you want to regroup the current information to receive the sum of grades. It seems the the information comes form a databases, so why don't you GROUP BY and sum on database level?

Anyway. Here's an approach. Start by keeping a map of student_course_id => score. First it will be empty: $map = [];

Then start iterating through the whole structure e.g. foreach ($data as $row. For each row, you need to check all the corresponding grade_items e.g. foreach ($row['grade_items'] as $gradeItem). Now you need to check whether the student_course_id from the grade item is present into the mapping.

If it's not present, create it with starting value of zero e.g.

if (!key_exists($gradeItem['student_course_id'], $map)) { 
    $map[$gradeItem['student_course_id']] = 0;
}

Once you ensure that the student_course_id is present, you can just add to the previous value the current score => $map[$gradeItem['student_course_id']] += $gradeItem['score'].

Royal Bg
  • 6,988
  • 1
  • 18
  • 24
  • Hmmm! this is a very good approach. I'd try it out now and get back to you. What you said about regrouping it and summing on database level got my attention too. I will look into that also. – Pogo Apr 23 '20 at 00:32
  • This worked! So I took your advice and regrouped and summed on database level. So I got all the ```grade_items``` from the arrays I was interested in and groupedBy the ```student_course_id``` then looped through each group and got the sum, then I instantiated the ```result_item``` model and saved the score as the sum of the group. – Pogo Apr 23 '20 at 01:06
  • So my grouping looked like this ``` array:1 [ 11 => array:2 [ 0 => array:7 [ "id" => 5 "gradelist_id" => 9 "student_course_id" => 11 "score" => 8 ] 1 => array:7 [ "id" => 6 "gradelist_id" => 10 "student_course_id" => 11 "score" => 0 ] ] ] ``` – Pogo Apr 23 '20 at 01:09
  • then I did this. ``` foreach ($grade_items as $key => $grade_item) { $sum = $grade_item->sum('score'); $result_item = new ResultItem(); $result_item->student_course_id = $key; $result_item->score = $sum; $result_item->save(); } ``` – Pogo Apr 23 '20 at 01:09
1

Here is a sample data i used

$array = [
        [
            'id' => 9,
            'course_id' => 6,
            'semester_id' => 2,
            'name' => 'Assignment',
            'total_score' => 10,
            'grade_items' => [
                [
                    'id' => 5,
                    'gradelist_id' => 9,
                    'student_course_id' => 11,
                    'score' => 8,
                    'created_at' => '2020-04-21T03:31:20.000000Z',
                    'updated_at' => '2020-04-21T20:04:10.000000Z',
                ],
                [
                    'id' => 5,
                    'gradelist_id' => 9,
                    'student_course_id' => 15,
                    'score' => 15,
                    'created_at' => '2020-04-21T03:31:20.000000Z',
                    'updated_at' => '2020-04-21T20:04:10.000000Z',
                ]
            ]
        ],
        [
            'id' => 10,
            'course_id' => 6,
            'semester_id' => 2,
            'name' => 'Pop Quiz',
            'total_score' => 20,
            'grade_items' => [
                [
                    'id' => 6,
                    'gradelist_id' => 10,
                    'student_course_id' => 11,
                    'score' => 21,
                    'created_at' => '2020-04-22T00:11:17.000000Z',
                    'updated_at' => '2020-04-22T00:11:17.000000Z',
                ],
                [
                    'id' => 6,
                    'gradelist_id' => 10,
                    'student_course_id' => 23,
                    'score' => 15,
                    'created_at' => '2020-04-22T00:11:17.000000Z',
                    'updated_at' => '2020-04-22T00:11:17.000000Z',
                ]
            ]
        ]
    ];

and here is the code;

    $id = 0;

    return collect($array)
        ->flatMap(function ($item){
            return $item['grade_items'];
        })
        ->groupBy('student_course_id')
        ->transform(function ($subItems, $courseId) use (&$id) {
            $id++;

            return [
                'id' => $id,
                'student_course_id' => $courseId,
                'score' => $subItems->sum('score')
            ];
        })
        ->values()
        ->toArray();

here is the result;

        [
            [
                'id' => 1,
                'student_course_id' => 11,
                'score' => 29,
            ],
            [
                'id' => 2,
                'student_course_id' => 15,
                'score' => 15,
            ],
            [
                'id' => 3,
                'student_course_id' => 23,
                'score' => 15,
            ]
        ]
Ersoy
  • 8,816
  • 6
  • 34
  • 48
0

Use the sum() function. You can loop through the array, and do any checks you need, like if it is not Null etc, and pluck() it and then sum() it.

GabMic
  • 1,422
  • 1
  • 20
  • 37
  • Doing this would only give me access to the subarray in an array and not across all arrays. I want to sum values from the two arrays, not within the subarray. Like. sum all the grade_items in all arrays where the student_course_id's are equal. – Pogo Apr 22 '20 at 23:57
0

May I suggest recursivity approach?

<?php 
    function rec_sum_grades(&$array_grades, &$sum = 0){
      $sum += $array_grades['total_score'];
      if(!empty($array_grades['grade_items'])){
      $this->rec_sum_grades($array_grades['grade_items'], $sum);
    }
  }
  rec_sum_grades($array_grades, $sum);
  echo $sum;
?>
LuisE
  • 553
  • 3
  • 18
  • Hmmm... the issue here is that it would add across grade_items with different student_course_id's instead of items with the same student_course_id. But after grouping the grade_items by student_course_id, then this would work for me. Thank you! – Pogo Apr 23 '20 at 01:12