0

Now, maybe it is because I am tired, but in the last hour I had put myself in a loop-vortex trying to arrange an array in a different way (array_column(), array_map(), and a handful of foreach() and if() ) - and the result of this vortex were loops so confusing that I can not see the trees from the forest anymore, and frankly - I am ashamed to even post the spaghetti code that I have tried :-).

The array looks like this :

array (
  0 => 
  array (
    0 => '29',
    1 => '0m9-cart-main-app',
    2 => '2108',
    3 => '9',
  ),
  1 => 
  array (
    0 => '16',
    1 => '0m9-safe-box-server',
    2 => '2017',
    3 => '12',
  ),
  2 => 
  array (
    0 => '2',
    1 => '0m9art-main-app-nodejs',
    2 => '2017',
    3 => '2',
  ),
  3 => 
  array (
    0 => '1',
    1 => '0m9art-server-golang',
    2 => '2017',
    3 => '4',
  ),
  4 => 
  array (
    0 => '17',
    1 => '0m9panel',
    2 => '2017',
    3 => '7',
  ),
  5 => 
  array (
    0 => '3',
    1 => 'moli-server',
    2 => '2017',
    3 => '3',
  ),
  6 => 
  array (
    0 => '2',
    1 => 'igcc',
    2 => '2017',
    3 => '11',
  ),
  7 => 
  array (
    0 => '26',
    1 => '0m9-cart-main-app',
    2 => '2108',
    3 => '10',
  ),
  8 => 
  array (
    0 => '18',
    1 => '0m9-safe-box-python-app',
    2 => '2108',
    3 => '12',
  ),
  9 => 
  array (
    0 => '1',
    1 => '0m9art-evergreen-android-app',
    2 => '2108',
    3 => '5',
  ),  ......

The array goes on ( about 700 lines ) where array[0] = count , array[1] = name,array[2] = year,array[3] = month it's basically an aggregation of all commits in all git repositories of a single person and the goal is to have an approximation of per-project workload distribution each month ..

what I need is to know for each MONTH of YEAR what is the approximate percentage of NAME-COUNT ( repos-commits) from total MONTH-COUNT-OF-ALL-NAMES (monthly overall commits ).

so , I am sure there is an elegant one-liner to solve this horrible array, but I just can not seem to be able to do that anymore..

EDIT I

I am pretty sure that what I have done will only confuse everyone more, but since comments have asked - here are some of my tries in rearranging the array :

the array is originated from a csv , so

$csv = array_map('str_getcsv', file('git_stati.csv'));

give the original array posted above..

    `
// try I
foreach($csv as $line){
            $i=1;
            // $r_date[] = $line[2]  . $line[3] ;
            $r_date = $line[2]  .'-'. $line[3] ;
            $r_dater[$r_date.'-'.$line[1] ] = $line[0]  ;
            $r_new[$line[1]]= $line[0] ;
            $i++;
    }

    `// try II
    foreach($csv as $line){
        if ( $line[2] == '2018' ){
        $name[] = $line[1] ;
        $count[$line[1] ] += $line[0];
        }
        if ( $line[2] == '2017' ){
        $name[] = $line[1] ;
        $count[$line[1] ] += $line[0];
        }
    }


   // try III
    // foreach($r_dater as $key => $val) {
        // if(substr($key, 0, 6) == '2018-9'){
        // $str2 = substr($key, 7);
            // $special_items[$key] = $val;
            // $repo_r[$str2]=  $val;

            // }
    // } 

// other failed confusing trials ...

highlight_string("<?php\n\$data =\n". var_export($r_dater, true) . ";\n?>");

EDIT II

it's basically an aggregation of all commits in all git repositories of a single person and the goal is to have an approximation of per-project workload distribution each month ..

what I need is to know for each MONTH of YEAR what is the approximate percentage of NAME-COUNT ( repos-commits) from total MONTH-COUNT-OF-ALL-NAMES (monthly overall commits ).

For the example array, the desired output is something like :

'2018-09 => array ( 'repo_name' => '0m9-cart-main-app', 'commits' => 29, '% of total commits for 2018-09 => 'x.xx%', ),

3
  • 1
    Put what you have tried in the question Commented Oct 15, 2018 at 11:48
  • Should MONTH-COUNT-OF-ALL-NAMES be computed per year? Commented Oct 15, 2018 at 11:49
  • Loop over it once, to sum up the counts for each year/month combination, put that into a new array. Then, loop over the original a second time, to calculate the percentage of the given value of an item in regard to the overall sum for the year/month that you just calculated … Whether you modify the original array to contain that percentage value afterwards as well, or write them into a new array - up to you … (you didn’t specify.) Commented Oct 15, 2018 at 11:52

3 Answers 3

1

Solution:

Calcultaion is made using two arrays - one for product count per period, the other for total count per period.

PHP:

<?php
# Input
$input = array(
  array (
    0 => '20',
    1 => '0m9-cart-main-app',
    2 => '2108',
    3 => '9',
  ),
  array (
    0 => '30',
    1 => '0m9art-main-app-nodejs',
    2 => '2108',
    3 => '9',
  ),
  array (
    0 => '20',
    1 => '0m9-cart-main-app',
    2 => '2108',
    3 => '10',
  ),
  array (
    0 => '2',
    1 => '0m9art-main-app-nodejs',
    2 => '2108',
    3 => '10',
  )
);

# Calculate product and total counts
$monthProducts = array();
$monthTotal = array();
foreach($input as $item) {
    $count = $item[0];
    $name  = $item[1];
    $year  = $item[2];
    $month = $item[3];
    $period = $year.'-'.$month;
    if (!array_key_exists($period, $monthTotal)) {
        $monthTotal[$period] = 0;   
    }
    $monthTotal[$period] += $count;
    if (!array_key_exists($period, $monthProducts)) {
        $monthProducts[$period] = array();  
    }
    if (!array_key_exists($name, $monthProducts[$period])) {
        $monthProducts[$period][$name] = 0; 
    }
    $monthProducts[$period][$name] += $count;   
}   

# Approximate percentage and output by period
foreach($monthProducts as $period => $products) {
    echo $period."<br>";
    foreach($products as $name => $count) {
        echo "Product '". $name. "' approximate percentage: ". round($count / $monthTotal[$period] * 100, 2), " %. <br>";
    }
}
?>
Sign up to request clarification or add additional context in comments.

1 Comment

tnx, more procedural makes easy for this late :-). I was wrongly forcing myself to put all in one array.
1

You can compute your MONTH-COUNT-OF-ALL-NAMES with array_reduce after first finding all the unique years:

 $years = array_unique(array_column($data, 2));
 $mcoan = array_reduce($data, 
                       function ($c, $d) { 
                           $c[$d[2]] += (int)$d[0]; 
                           return $c;
                       }, 
                       array_combine($years, array_fill(0, count($years), 0)));

this gives an array like:

Array ( [2108] => 74 [2017] => 41 )

Then you can add a percentage to each entry in your array using array_map:

 $data = array_map(function ($v) use ($mcoan) {
                       $v[4] = round($v[0]/$mcoan[$v[2]]*100,2); 
                       return $v;
                       }, 
                   $data);

Output (for your small sample):

array (
  0 => 
  array (
    0 => '29',
    1 => '0m9-cart-main-app',
    2 => '2108',
    3 => '9',
    4 => 39.19,
  ),
  1 => 
  array (
    0 => '16',
    1 => '0m9-safe-box-server',
    2 => '2017',
    3 => '12',
    4 => 39.02,
  ),
  2 => 
  array (
    0 => '2',
    1 => '0m9art-main-app-nodejs',
    2 => '2017',
    3 => '2',
    4 => 4.88,
  ),
  3 => 
  array (
    0 => '1',
    1 => '0m9art-server-golang',
    2 => '2017',
    3 => '4',
    4 => 2.44,
  ),
  4 => 
  array (
    0 => '17',
    1 => '0m9panel',
    2 => '2017',
    3 => '7',
    4 => 41.46,
  ),
  5 => 
  array (
    0 => '3',
    1 => 'moli-server',
    2 => '2017',
    3 => '3',
    4 => 7.32,
  ),
  6 => 
  array (
    0 => '2',
    1 => 'igcc',
    2 => '2017',
    3 => '11',
    4 => 4.88,
  ),
  7 => 
  array (
    0 => '26',
    1 => '0m9-cart-main-app',
    2 => '2108',
    3 => '10',
    4 => 35.14,
  ),
  8 => 
  array (
    0 => '18',
    1 => '0m9-safe-box-python-app',
    2 => '2108',
    3 => '12',
    4 => 24.32,
  ),
  9 => 
  array (
    0 => '1',
    1 => '0m9art-evergreen-android-app',
    2 => '2108',
    3 => '5',
    4 => 1.35,
  ),
)

1 Comment

That is an elegant solution to my mess :-) like I commented above, your answer and @misorude seem a bit different but produces same results .. Now I have the conundrum of who's answer to accept . :-)
1

Assuming your original array is called $data (and that I understood what you want to begin with, not totally sure), you can do it like this:

// sum up values for year and month in two-dimensional array
$sums = [];
foreach($data as $item) {
  if(isset($sums[$item[2]][$item[3]])) {
    $sums[$item[2]][$item[3]] += $item[0]; // add value, if entry for year and month already exists,
  }
  else {
    $sums[$item[2]][$item[3]] = $item[0]; // otherwise assign as initial value
  }
}

// update original array, adding calculated percentage as $item[4]
foreach($data as &$item) {
  $item[4] = ($item[0] / $sums[$item[2]][$item[3]] * 100);
}
unset($item); // working with a reference above, so don’t forget to unset

var_dump($data);

Now for the example data you have shown, that simply results in a value of 100 for each item, because there was no more than one entry per year-month combination in the first place. But if you modify the input data to produce appropriate test cases, you’ll see the numbers changing accordingly.

Again, not sure if that is exactly what you wanted, question is a bit vague in that regard.

1 Comment

I am sorry if I was not so clear, I edited a bit, but yep .. your answer sure helps to put some clarity into my tired-confused mind .. funny thing - your answer and @nick answer have different approaches but same result . :-)

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.