问题
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