Php - сортировка существующих массивов и значений агрегированных ключей - PullRequest
0 голосов
/ 15 октября 2018

Теперь, может быть, это потому, что я устал, но в последний час я поставил себя в круговорот, пытаясь упорядочить массив по-другому (array_column(), array_map() и несколько foreach() и if()) - и результат этого вихря оказался настолько запутанным, что я больше не вижу деревьев в лесу, и, честно говоря, мне стыдно даже публиковать код спагетти, который я пробовал :-).

Массив выглядит так:

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',
  ),  ......

Массив продолжается (около 700 строк), где array[0] = count, array[1] = name, array[2] = year, array[3] = month это в основном агрегациявсех коммитов во всех git-репозиториях одного человека, и цель состоит в том, чтобы каждый месяц иметь приблизительное распределение рабочей нагрузки для каждого проекта.

что мне нужно знать для каждого MONTH из YEARкаков примерный процент NAME-COUNT (репо-коммитов) от общего числа MONTH-COUNT-OF-ALL-NAMES (ежемесячный общий коммит).

так что я уверен, что есть элегантный однострочный, чтобы решить этот ужасный массив, ноЯ просто не могу сделатьчто больше ..

РЕДАКТИРОВАТЬ I

Я почти уверен, что то, что я сделал, только еще больше запутает всех, но так как комментарии спросили - вот некоторые из моихпытается переставить массив:

массив получен из csv, поэтому

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

дают исходный массив, размещенный выше ..

    `
// 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?>");

РЕДАКТИРОВАТЬ II

Это, по сути, агрегация всех коммитов во всех git-репозиториях одного человека, и цель состоит в том, чтобы каждый месяц иметь приблизительное распределение распределения нагрузки по проекту

мне нужно знать для каждого MONTH из YEAR каков приблизительный процент NAME-COUNT (репо-коммитов) от общего числа MONTH-COUNT-OF-ALL-NAMES (ежемесячный общий коммит).

Для примера массива желаемый вывод будет выглядеть примерно так:

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

Ответы [ 3 ]

0 голосов
/ 15 октября 2018

Предполагая, что ваш исходный массив называется $ data (и я понял, с чего вы хотите начать, не совсем уверен), вы можете сделать это следующим образом:

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

Теперь для примера данных, которые выпоказали, что это просто приводит к значению 100 для каждого элемента, поскольку в первую очередь не было более одной записи на комбинацию год-месяц.Но если вы измените входные данные для получения соответствующих тестовых случаев, вы увидите, что числа меняются соответствующим образом.

Опять же, не уверен, что это именно то, что вам нужно, вопрос немного расплывчат в этом отношении.

0 голосов
/ 15 октября 2018

Решение:

Расчет производится с использованием двух массивов - один для подсчета продуктов за период, другой для общего подсчета за период.

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>";
    }
}
?>
0 голосов
/ 15 октября 2018

Вы можете вычислить MONTH-COUNT-OF-ALL-NAMES с помощью array_reduce после первого нахождения всех уникальных лет:

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

это дает массив, подобный:

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

Затем вы можете добавитьпроцентное отношение к каждой записи в вашем массиве, используя array_map:

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

Вывод (для небольшой выборки):

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,
  ),
)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...