Group PHP array numbers

六月ゝ 毕业季﹏ 提交于 2020-06-12 06:23:57

问题


How I can change this:

Array
(
    [0] => 1
    [1] => 2
    [2] => 3
    [3] => 4
    [4] => 5
    [5] => 6
    [6] => 7
    [7] => 11
    [8] => 21
    [9] => 22
    [10] => 23
    [11] => 24
)

To this:

1-7, 11, 21-24

I have a list of numbers like this in PHP array, and I just want to make this list a little bit smaller.

2000: 3 6 7 11 15 17 25 36 42 43 45
2001: 2 3 4 5 6 9 10 11 12 13 34 37 45 46 47 48 49 50 51 52
2002: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 33 34 35 36 37 39 40 41 42 43 44 45 46 47 48 49 50 51 52
2003: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
2004: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 19 21 22 23 24 25 26 27 28 29 30 31 32 33 34 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
2005: 1 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
2006: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
2007: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

回答1:


Interesting task.

Here's a demo script that does exactly what you want.

Tweak to taste.

Code

<?php

$groups = array();
$active_group = 0;

$output = array();
$output_counter = 0;

$nums = array( 1, 2, 3, 4, 5, 6, 7, 11, 21, 22, 23, 24 );


foreach( $nums as $k => $num ) {

    // if this isn't the first item, and the current number
    // isn't one more than the previous one, increment the counter
    if( $k !== 0 && $nums[$k] !== $nums[$k-1]+1 )
        $active_group ++;

    // add this number to a group
    $groups[ $active_group ][] = $num;

}


// take the 1st and last of each group
foreach( $groups as $group ) {

    $first = array_shift( array_values($group) );
    $output[$output_counter][] = $first;

    $last = array_pop( array_values($group) );
    if( $first !== $last )
        $output[$output_counter][] = $last;

    $output_counter++;

}


echo '<pre>';
print_r($output);

?>

Output

Array
(
    [0] => Array
        (
            [0] => 1
            [1] => 7
        )

    [1] => Array
        (
            [0] => 11
        )

    [2] => Array
        (
            [0] => 21
            [1] => 24
        )

)



回答2:


A single loop will do. You need need to keep track of the "previous" iteration's value and the "starting" value for storing ranged data.

Code:

$prev = -1;                                                    // initialize out of range
foreach ($numbers as $n) {
    if (!isset($start)) {                                      // first iteration
        $start = $n;                                           // declare $start
    } elseif ($n != $prev + 1) {                               // not consecutive
        $result[] = $start == $prev ? $prev : "$start-$prev";  // store single or ranged values
        $start = $n;                                           // update $start
    }
    $prev = $n;                                                // declare / update $prev
}
$result[] = $start == $prev ? $prev : $start . '-' . $prev;    // store final iteration data
echo implode(', ', $result);                                   // comma delimit the values

Output from: $numbers = [1, 2, 3, 4, 5, 6, 7, 11, 21, 22, 23, 24]; (Demo)

1-7, 11, 21-24

Output from: $numbers = [1, 3, 5, 6, 11, 21, 22, 23, 24, 26]; (Demo)

1, 3, 5-6, 11, 21-24, 26



回答3:


Here is a way to both compress an array of integers into the string format you want and to expand that string format back out to an array of integers.

function compress($expanded) {
    $low = -1;
    $prevNum = -1;
    $expanded = array_unique($expanded);
    sort($expanded, SORT_NUMERIC);
    foreach($expanded as $num) {
        if($low == -1) {
            $low = $num;
        } else if($num - $prevNum > 1) { 
            $compact[] = ($prevNum - $low >= 1) ? sprintf("%d-%d", $low, $prevNum) : $prevNum; 
            $low = $num;
        } 
        $prevNum = $num;
    }
    if($low != -1 ) {
        $compact[] = ($num - $low >= 1) ? sprintf("%d-%d", $low, $num) : $num; 
    }
    return implode(",", $compact);
}

public static function expand($compact) {
    $expanded = Array();
    $compact = explode(",", $compact);
    foreach($compact as $num) {
        if( is_numeric($num) ) {
            $expanded[] = $num;
        } else {
            list($low, $high) = explode("-", $num);
            if( is_numeric($low) && is_numeric($high) && $low < $high) {
                for($i = $low;$i <= $high;$i++) {
                    $expanded[] = $i;
                }
            }
        }
    }
    return $expanded;
}



回答4:


//Placeholder array
$b = array();

// Slice array (where to slice)
$s = array(11, 21);

foreach ($array as $year => $a) {
    for($i = 0; $i < count($a); $i++) {
        for($ii = 0; $ii < count($s); $ii++) {
            if($i == 0) {
                $b[$year]['<' . $s[$ii]][] = $a[$i];
                break;
            } else if ( isset($a[$i+1]) && $a[$i] < $s[$ii] && $a[$i+1] >=$s[$ii]){
                $b[$year]['<' . $s[$ii]][] = $a[$i];
                if (isset($s[$ii+1])) {
                    $b[$year]['<' . $s[$ii+1]][] = $a[$i+1];
                } else {
                    $b[$year]['>' . $s[$ii]][] = $a[$i+1];
                }
                break;
            } else if ( !isset($s[$ii+1]) && $i == count($a) - 1) {
                $b[$year]['>' . $s[$ii]][] = $a[$i];
                break;
            }
        }
    }
}

$array

The list of numbers

OUTPUT ($b):

array
  2000 => 
    array
      '<11' => 
        array
          0 => int 3
          1 => int 7
      '<21' => 
        array
          0 => int 11
          1 => int 17
      '>21' => 
        array
          0 => int 25
          1 => int 45
  2001 => 
    array
      '<11' => 
        array
          0 => int 2
          1 => int 10
      '<21' => 
        array
          0 => int 11
          1 => int 13
      '>21' => 
        array
          0 => int 34
          1 => int 52
  2002 => 
    array
      '<11' => 
        array
          0 => int 1
          1 => int 10
      '<21' => 
        array
          0 => int 11
          1 => int 20
      '>21' => 
        array
          0 => int 21
          1 => int 52
  2003 => 
    array
      '<11' => 
        array
          0 => int 1
          1 => int 10
      '<21' => 
        array
          0 => int 11
          1 => int 20
      '>21' => 
        array
          0 => int 21
          1 => int 51
  2004 => 
    array
      '<11' => 
        array
          0 => int 1
          1 => int 10
      '<21' => 
        array
          0 => int 11
          1 => int 19
      '>21' => 
        array
          0 => int 21
          1 => int 52
  2005 => 
    array
      '<11' => 
        array
          0 => int 1
          1 => int 10
      '<21' => 
        array
          0 => int 11
          1 => int 20
      '>21' => 
        array
          0 => int 21
          1 => int 52
  2006 => 
    array
      '<11' => 
        array
          0 => int 1
          1 => int 10
      '<21' => 
        array
          0 => int 11
          1 => int 20
      '>21' => 
        array
          0 => int 21
          1 => int 52
  2007 => 
    array
      '<11' => 
        array
          0 => int 1
          1 => int 10
      '<21' => 
        array
          0 => int 11
          1 => int 20
      '>21' => 
        array
          0 => int 21
          1 => int 52

NOTE: Just change the values (11) and (21) to suit your needs. You can add more values.




回答5:


Heres an example:

$query = "SELECT '1-11' Range, COUNT(rank) rank 
    FROM promoted WHERE rank between 1 and 11 
    union all 
    SELECT '12-21' Range, COUNT(rank) rank 
    from promoted 
    where rank between 12 and 21 
    union all 
    SELECT '22-31' Range, count(rank) rank 
    from promoted 
    where rank between 22 and 31 
    union all 
    SELECT '32-40' Range, count(rank) rank 
    from promoted 
    where rank between 22 and 31 
    union all 
    SELECT rank, count(rank) FROM promoted WHERE rank = '40'";  


来源:https://stackoverflow.com/questions/11875006/group-php-array-numbers

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!