1

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

1 Answer 1

1

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]
Sign up to request clarification or add additional context in comments.

9 Comments

@Rigal sorry I accidentally changed my sort. See my edit
@Rigal I've just made another edit to give numeric keys for the internal arrays if that's your preference
Thnak you so much for your quick help. I want object intesd of every single array. IE ['Andew',0, 480, 600].
@Rigal my output is exactly what you asked for in your question.
Yes but I want to convert in object to display chart so I need ['Andew',0, 480, 600],['john',120,0,150],['Walid',0,0,160] .Would you please suggest me to convest in same object format?
|

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.