Rigal
Rigal

Reputation: 631

Group by array using multiple values and sum of array based on group values in loop and sorting array

I want to group array values and find total (sum of array value-based of the group by value) and then sort array based on total. I want to group by users by fund type ("Private, VC, Others") and the sum of total fund ("last value")

I have set up a demo link here.

https://3v4l.org/6WNKE

<?php

$data = [
  [
    'Jon',
    'NO',
    "",
    "Private",
    120
  ],
  [
    'Andew',
    'NO',
    "",
    "VC",
    150
  ],
  [
    'Walid',
    'YES',
    "",
    "Other",
    160
  ],

  [
    'Andew',
    'YES',
    "",
    "VC",
    150
  ],
  [
    'Andew',
    'YES',
    "",
    "VC",
    180
  ],

  [
    'Jon',
    'NO',
    "",
    "Other",
    150
  ],

  [
    'Andew',
    'YES',
    "",
    "Other",
    600
  ]
];

$arr = array();
foreach ($data  as $key => $item) {
      $arr[$item[0]][$key] =   $item['4'];
}

var_dump($arr);

I want below output

Group by ("Private, VC, Others") so value format like [sum of the private, sum of VC, a sum of Others ]

Array
(
    [Jon] => [120,110,0]
    [Andew] => [0,480,600]
    [Walid] => [0,0,160]
)

And then I want to sort array based on the total sum

Array
(
 [Andew] => [0,480,600]
 [Jon] => [120,110,0]
 [Walid] => [0,0,160]
)

Anyone please suggest possible solution to fic this issue?

Thanks

Upvotes: 1

Views: 125

Answers (1)

Nick
Nick

Reputation: 147146

If this is the result of a database query, this could almost certainly have been done more efficiently in that query. However, you can get the results you want in 3 stages:

  1. group input data by person and type
    $arr = array();
    foreach ($data  as $key => $item) {
        $arr[$item[0]][$item[3]] = ($arr[$item[0]][$item[3]] ?? 0) + $item[4];
    }
  1. fill in the missing values for each person
    foreach (array_unique(array_column($data, 3)) as $type) {
        foreach ($arr as &$person) {
            if (!isset($person[$type])) $person[$type] = 0;
        }
    }
  1. Sort the array
    uasort($arr, function ($a, $b) {
        return $b['Private'] + $b['Other'] + $b['VC'] - ($a['Private'] + $a['Other'] + $a['VC']);
    });

Output (for your sample data):

Array
(
    [Andew] => Array
        (
            [VC] => 480
            [Other] => 600
            [Private] => 0
        )
    [Jon] => Array
        (
            [Private] => 120
            [Other] => 150
            [VC] => 0
        )
    [Walid] => Array
        (
            [Other] => 160
            [Private] => 0
            [VC] => 0
        )
)

Demo on3v4l.org

Note I've left the keys of the inner array as associative as that seems more useful. If you would prefer numeric keys, you would need to sort each internal array so the keys were in the same order, and then take array_values of each entry:

$key_rank = array('Private' => 0, 'VC' => 1, 'Other' => 2);
foreach ($arr as &$person) {
    uksort($person, function ($a, $b) use ($key_rank) {
        return $key_rank[$a] - $key_rank[$b];
    });
    $person = array_values($person);
}

Output:

Array
(
    [Andew] => Array
        (
            [0] => 0
            [1] => 480
            [2] => 600
        )    
    [Jon] => Array
        (
            [0] => 120
            [1] => 0
            [2] => 150
        )    
    [Walid] => Array
        (
            [0] => 0
            [1] => 0
            [2] => 160
        )    
)

Demo on 3v4l.org

To get the results in the form of an array with the name and values together, replace the last piece of code with this:

$key_rank = array('Private' => 0, 'VC' => 1, 'Other' => 2);
$result = array();
foreach ($arr as $name => &$person) {
    uksort($person, function ($a, $b) use ($key_rank) {
        return $key_rank[$a] - $key_rank[$b];
    });
    $result[] = array_merge(array($name), array_values($person));
}

print_r($result);

Output:

Array
(
    [0] => Array
        (
            [0] => Andew
            [1] => 0
            [2] => 480
            [3] => 600
        )
    [1] => Array
        (
            [0] => Jon
            [1] => 120
            [2] => 0
            [3] => 150
        )
    [2] => Array
        (
            [0] => Walid
            [1] => 0
            [2] => 0
            [3] => 160
        )
)

[Demo on 3v4l.org][3]

Upvotes: 1

Related Questions