【问题标题】:Grouping Broken series from an array从数组中对损坏的系列进行分组
【发布时间】:2020-03-13 11:41:19
【问题描述】:

我需要对损坏的系列进行分组。

//Example
$seriesArray = array(1, 2, 3, 5, 7, 8, 11, 12, 15);
//You see numbers are not continuous here.
//Therefore i need to group the above array to seek the below output

预期输出

Series 1 : from 1 to 3
Series 2 : 5
Series 3 : 7 and 8
Series 4 : 11 and 12
Series 5 : 15

在上面的示例中,您可以看到,系列 1 是从 1 到 3 分组的(因为有大于 2 个值),而在系列 2 和 5 中,由于没有连续性,显示单个值。在系列 3 和系列 4 中,它显示了 2 个值,具有两个连续的值。

我尝试过的

function groupSeries($mainArray, $comboArr=array()) {
   $getRange = range(min($mainArray), max($mainArray)); //Expected Range
   $diffArr  = array_diff($getRange, $mainArray); //Difference of what is expected
   $ranges   = array();
   $initiateKey = 0;
   foreach($diffArr as $indKey=>$indVal) {
      if(!empty($mainArray[$initiateKey])) {
         $ranges[] = range($mainArray[$initiateKey], $getRange[$indKey-1]);
         $initiateKey = $indKey;
      }
   }
   return showRanges($ranges);
}
function showRanges($getRanges) {
   $i = 1;
   foreach($getRanges as $indRange) {
     $arrCount = count($indRange);
     echo "Series $i : ";
     switch($arrCount) {
        case 1 : echo $indRange[0]; break;
        case 2 : echo $indRange[0]." and ".$indRange[1]; break;
        default: echo "From ".min($indRange)." to ".max($indRange); break;
     }
     $i++;
     echo "\n";
   }
}

$seriesArray = array(1, 2, 3, 5, 7, 8, 11, 12, 15);
groupSeries($seriesArray);

上述系列数组失败,当前输出为

Series 1 : From 1 to 3
Series 2 : 5
Series 3 : 8
Series 4 : From 9 to 15

上述试验适用于某些场景,但在许多情况下都失败了。

【问题讨论】:

  • 能否提供一个失败的场景?
  • 上面提到的数组本身是失败的,如果有更多的连续性,它工作得很好..

标签: php arrays series numeric


【解决方案1】:

这也应该有效 -

    $seriesArray = array(1, 2, 3, 5, 7, 8, 11, 12, 15);
    sort($seriesArray); // Sort array if required
    $all = range(min($seriesArray), max($seriesArray)); // get all possibles values in sorted manner
    $temp = array_diff($all, $seriesArray); // get the missing values
    $new = [];
    $i = 1;
    foreach ($temp as $missing) {
        // Group or extract all values present less than or equals to every missing value to get the series
        $new[$i] = array_filter($seriesArray, function($v) use($missing) {
            return $v <= $missing;
        });
        // remove already grouped values
        $seriesArray = array_diff($seriesArray, $new[$i]);
        $i++;
    }
    // merge the remaining values or end values & remove empty values
    $new = array_filter(array_merge($new, [$seriesArray]));

$new会有所有的分组值,你可以随意表示。

【讨论】:

  • 感谢@sougata-bose,我将您的解决方案标记为我的答案,因为这里使用了缺失值。
  • @ameenulla0007 初始数组的最大可能大小是多少?我问这个是因为这个解决方案的时间复杂度似乎是二次的(O(n^2))。如果它们很小(不超过 1000 个左右),那么这很好。
  • 这取决于缺少多少值。循环运行缺失的值。
【解决方案2】:

所有检查或使用索引来访问其他答案中发生的正确元素似乎仍然有点令人费解,我会选择

function groupSeries($array) {
   $ranges = [];
   $idx = -1;
   $prev = false;
   foreach($array as $val) {
     if($prev === false || $val != $prev+1) {
       $idx++;
     }
     $ranges[$idx][] = $val;
     $prev = $val;
   }
   return showRanges($ranges);
}

这真的不需要更多,只是根据与前一个值的差异是否为 1 来推进将值放入结果数组中的位置的索引。

【讨论】:

    【解决方案3】:

    请看看这个方法。我希望它的想法不简单。如果我遗漏了什么,请告诉我:

    function groupSeries2($mainArray){
        sort($mainArray);
        $groups=[];
        $group_start=$mainArray[0];
        $group_last=$group_start;
        foreach ($mainArray as $value) {
            if($group_last+1 == $value){
                //continuous series
                $group_last=$value;
            }
            else{
                //interrupted series
                $groups[]=[$group_start,$group_last];
                $group_start=$value;
                $group_last=$group_start;
            }
        }
        $groups[]=[$group_start,$group_last];
        array_shift($groups);
        foreach ($groups as $group_key => $group){
            $groups[$group_key] = range($group[0],$group[1]);
        }
        return $groups;
    }
    

    【讨论】:

      【解决方案4】:

      你可以试试下面的代码

      $seriesArray = array(1, 2, 3, 5, 7, 8, 11, 12, 15);
      sort($seriesArray);
      $result = array();
      
      $indx = 0;
      foreach($seriesArray as $key => $val){
          $tmp  = $seriesArray[$key];
          $next = (isset($seriesArray[$key+1]))? $seriesArray[$key+1] : '';
          if($next != ''){
              if(!isset($result[$indx])) $result[$indx] = array();
              if(($tmp+1) == $next ){
                  $result[$indx][] = $tmp;
              }else{
                  $result[$indx][] = $tmp;
                  $indx++;
      
              }
          }else{
              $result[$indx][] = $tmp;    
          }
      
      }
      foreach($result as $key => $val){
          echo "Series ".($key+1)."  : ".implode(",",$result[$key])."<br>";
      }
      print_r($result);
      

      Demo Link

      【讨论】:

      • 感谢您的回答,但似乎最后一次迭代未能打印值为 15 的最后一个系列。
      • 现在看起来很酷,但它是否足够有效地迭代数组中的每个值。目前数组的长度很小。 :)
      • @ameenulla0007 但我相信在最坏的情况下,最少 n 迭代需要为 n 个元素的数组解决这个问题。我们也可以比较其他答案以获得优化的解决方案
      猜你喜欢
      • 2021-07-03
      • 1970-01-01
      • 2020-07-23
      • 2017-08-17
      • 2016-10-10
      • 2021-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多