range
(PHP 4, PHP 5, PHP 7, PHP 8)
range — ある範囲の要素を含む配列を作成する
説明
ある範囲の要素を含む配列を作成します。
start
と end
が両方文字列で、かつ step
が整数の場合、
生成される配列はバイト列のシーケンスになります。
そうでない場合、生成される配列は数値のシーケンスになります。
start
が end
よりも小さい場合、シーケンスは増加します。
そうでない場合、シーケンスは減少します。
パラメータ
start
-
シーケンスの最初の値。
end
-
シーケンスの最後としてあり得る値。
step
-
step
は、生成されるシーケンスの個別の値が どれくらい離れているかを指定します。シーケンスが減少する場合、
step
は負の値を指定しても構いません。step
が 端数のない float の場合、整数として解釈されます。
戻り値
要素のシーケンスを配列として返します。
最初の要素は start
になり、
end
になるまで続きます。
シーケンスのそれぞれの値は、step
だけ離れています。
返される配列の最後の要素は、
end
または シーケンスの直前の要素になります。
どちらになるかは、step
の値によります。
start
と end
が両方文字列で、かつ step
が整数の場合、
生成される配列は、バイト列のシーケンスになります。
一般的にはラテン文字の ASCII 文字からなるシーケンスです。
start
, end
, step
のうち少なくともひとつが float の場合、
生成される配列は float のシーケンスになります。
その他の場合、生成される配列は整数のシーケンスになります。
エラー / 例外
-
step
が0
の場合、ValueError がスローされます。 -
start
,end
,step
が有限の値(is_finite()) でない場合、 ValueError がスローされます。 -
step
が負の値なのに、生成される範囲が増えている(つまり、$start <= $end
) 場合、 ValueError がスローされます。 -
start
またはend
が空文字列''
の場合、E_WARNING
が発生し、空文字列は0
として解釈されます。 -
start
またはend
が 数値形式の文字列 でない、長さが1バイトより大きい値の場合、E_WARNING
が発生します。 -
start
またはend
が 暗黙のうちに整数にキャストされた文字列の場合、E_WARNING
が発生します。なぜなら、他の境界の入力値は数値だからです。 -
step
が float の場合、 かつstart
とend
が 数値形式の文字列 でない場合、E_WARNING
が発生します。
変更履歴
バージョン | 説明 |
---|---|
8.3.0 |
start と end
が両方文字列の場合、range() は常にバイト列を要素とした配列を生成するようになりました。
これより前のバージョンでは、境界の値のうちのひとつが数値形式の文字列の場合に、もう一方の境界の値を整数にキャストしていました。
|
8.3.0 |
start または end が
暗黙のうちに整数にキャストされた文字列の場合、
E_WARNING が発生するようになりました。
なぜなら、他の境界の入力値が数値だからです。
|
8.3.0 |
start または end
が数値形式の文字列でなく、かつ長さが1バイトより大きい値の場合、
E_WARNING が発生するようになりました。
|
8.3.0 |
start または end が空文字列の場合、E_WARNING が発生するようになりました。
|
8.3.0 |
step が 端数のない float
の場合、整数として解釈されるようになりました。
|
8.3.0 |
step が負の値なのに、生成される範囲が増えている場合、
ValueError がスローされるようになりました。
|
8.3.0 |
step が有限の値でない場合、
ValueError がスローされるようになりました。
|
8.3.0 |
start または end
が配列、object、resource の場合、
TypeError がスローされるようになりました。
これより前のバージョンでは、これらの値は暗黙のうちに整数にキャストされていました。
|
例
例1 range() の例
<?php
echo implode(', ', range(0, 12)), PHP_EOL;
echo implode(', ', range(0, 100, 10)), PHP_EOL;
echo implode(', ', range('a', 'i')), PHP_EOL;
echo implode(', ', range('c', 'a')), PHP_EOL;
echo implode(', ', range('A', 'z')), PHP_EOL;
?>
上の例の出力は以下となります。
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 a, b, c, d, e, f, g, h, i c, b, a A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, [, \, ], ^, _, `, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z
User Contributed Notes 30 notes
To create a range array like
Array
(
[11] => 1
[12] => 2
[13] => 3
[14] => 4
)
combine two range arrays using array_combine:
array_combine(range(11,14),range(1,4))
You might expect range($n, $n-1) to be an empty array (as in e.g. Python) but actually PHP will assume a step of -1 if start is larger than end.
So with the introduction of single-character ranges to the range() function, the internal function tries to be "smart", and (I am inferring from behavior here) apparently checks the type of the incoming values. If one is numeric, including numeric string, then the other is treated as numeric; if it is a non-numeric string, it is treated as zero.
But.
If you pass in a numeric string in such a way that is is forced to be recognized as type string and not type numeric, range() will function quite differently.
Compare:
<?php
echo implode("",range(9,"Q"));
// prints 9876543210
echo implode("",range("9 ","Q")); //space after the 9
// prints 9:;<=>?@ABCDEFGHIJKLMNOPQ
echo implode("",range("q","9 "));
// prints qponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:987654
?>
I wouldn't call this a bug, because IMO it is even more useful than the stock usage of the function.
The function will generate an array of integers even if your numerical parameters are enclosed in quotes.
<?php
var_dump( range('1', '2') ); // outputs array(2) { [0]=> int(1) [1]=> int(2) }
?>
An easy way to get an array of strings is to map strval() to the range:
<?php
var_dump( array_map('strval', range('1', '2')) ); // outputs array(2) { [0]=> string(1) "1" [1]=> string(1) "2" }
?>
<?php
function natural_prime_numbers(array $range, bool $print_info = false) : array {
$start_time = time();
$primes_numbers = array();
$print = '';
$count_range = count($range);
foreach($range as $number){
$values_division_number = array();
if($number === 0 || $number === 1 || !is_int($number)){ // eliminate 0, 1 and other no integer
continue;
}
if($number != 2 && $number%2 === 0){ // eliminate 2 and pairs numbers
continue;
}
for($i = 1; $i <= $number; $i++){
$resultado_divisao = $number / $i;
$values_division_number[$i] = $resultado_divisao;
if($count_range <= 20){ // $count_range <= 20 (+ performance)
$print .= PHP_EOL;
$info = 'The number '.$number.' divided by the number '.$i.' is equal to: '.($number / $i);
$print .= $info;
if($i === $number){
$print .= PHP_EOL;
}
}
array_walk($values_division_number, function($value, $index) use (&$values_division_number, &$number){ // reference change values
// eliminate floats and others numbers not are equal 1 and own number
if(is_float($value) && $value != $number && $value > 1){
unset($values_division_number[$index]);
}
});
$values_division_number = array_values($values_division_number); // reindex array
// here we want only array with 2 indexes with the values 1 and own number (rule to a natural prime number)
if(count($values_division_number) === 2 && $values_division_number[0] === $number && $values_division_number[1] === 1){
$primes_numbers[$number] = $number;
}
}
}
return array(
'length_prime_numbers' => count($primes_numbers),
'prime_numbers' => array_values($primes_numbers),
'print' => $print,
'total_time_processing' => (time() - $start_time).' seconds.',
);
}
var_dump(natural_prime_numbers(range(0, 11))); // here the range() function ;-)
// Result:
// array (size=3)
// 'length_prime_numbers' => int 5
// 'prime_numbers' =>
// array (size=5)
// 0 => int 2
// 1 => int 3
// 2 => int 5
// 3 => int 7
// 4 => int 11
// 'print' => string '
// O número 2 dividido pelo número 1 é igual a: 2
// O número 2 dividido pelo número 2 é igual a: 1
// O número 3 dividido pelo número 1 é igual a: 3
// O número 3 dividido pelo número 2 é igual a: 1.5
// O número 3 dividido pelo número 3 é igual a: 1
// O número 5 dividido pelo número 1 é igual a: 5
// O número 5 dividido pelo número 2 é igual a: 2.5
// O número 5 dividido pelo número 3 é igual a: 1.6666666666667
// O número 5 dividido pelo número 4 é igual a: 1.25
// O número 5 dividido pelo '...
// **************************** //
//
// * Remember that the function is recursive, that is: a range of 5000 takes more than 1 minute on a processor Intel® Core™ i5-8250U (3.40 GHz).
//
// **************************** //
?>
The function "range" is very useful to get an array of characters as range('C','R') does.
At work, I had to extend the function range($a,$b) to work in this special case: with two uppercase strings $a and $b, it should return all the possible strings between $a and $b.
This could be used for example to get the excel column indexes.
e.g. <?php range('A','AD') ==> array('A','B','C',...,'Z','AA','AB','AC','AD') ?>
So I wrote the function getrange($min,$max) that exactly does this.
<?php
function getcolumnrange($min,$max){
$pointer=strtoupper($min);
$output=array();
while(positionalcomparison($pointer,strtoupper($max))<=0){
array_push($output,$pointer);
$pointer++;
}
return $output;
}
function positionalcomparison($a,$b){
$a1=stringtointvalue($a); $b1=stringtointvalue($b);
if($a1>$b1)return 1;
else if($a1<$b1)return -1;
else return 0;
}
/*
* e.g. A=1 - B=2 - Z=26 - AA=27 - CZ=104 - DA=105 - ZZ=702 - AAA=703
*/
function stringtointvalue($str){
$amount=0;
$strarra=array_reverse(str_split($str));
for($i=0;$i<strlen($str);$i++){
$amount+=(ord($strarra[$i])-64)*pow(26,$i);
}
return $amount;
}
?>
foreach(range()) whilst efficiant in other languages, such as python, it is not (compared to a for) in php*.
php is a C-inspired language and thus for is entirely in-keeping with the lanuage aethetic to use it
<?php
//efficiant
for($i = $start; $i < $end; $i+=$step)
{
//do something with array
}
//inefficiant
foreach(range($start, $end, $step) as $i)
{
//do something with array
}
?>
That the officiant documentation doesnt mention the for loop is strange.
Note however, that in PHP5 foreach is faster than for when iterating without incrementing a variable.
* My tests using microtime and 100 000 iterations consistently (~10 times) show that for is 4x faster than foreach(range()).
Despite the line above that says that the $step value should be "given as a positive number," the range() function will in fact correctly handle reversed (decrementing) ranges. For example:
<?php print_r( range( 24, 20 ) ); ?>
Array
(
[0] => 24
[1] => 23
[2] => 22
[3] => 21
[4] => 20
)
<?php print_r( range( 20, 11, -3 ) ); ?>
Array
(
[0] => 20
[1] => 17
[2] => 14
[3] => 11
)
It will actually ignore the sign of the $step argument, and determine whether to increment or decrement based purely on whether $start > $end or $end > $start. For example:
<?php print_r( range( 20, 11, 3 ) ); ?>
Array
(
[0] => 20
[1] => 17
[2] => 14
[3] => 11
)
<?php print_r( range( 11, 20, -3 ) ); ?>
Array
(
[0] => 11
[1] => 14
[2] => 17
[3] => 20
)