Negative value of $step in range(), PHP - php

This is taken from the php.net manual for json_decode(), Example 4, 5th line from the bottom there:
foreach (range(4, 3, -1) as $depth)
I am not sure what is the purpose of that -1 there. I tried range(4, 3, 1) and range (4, 3, -1) and it gives the same results. The 1 in the first example is the default so it could be range(4, 3). I was only trying it with something like print_r(range(4, 3, -1); so the example on the php.net may be a different thing. I was looking on the Net and there is no info about it, or not right away.

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
)

Step is automatically cast to a positive number (yes, the manual is incorrect here)
So all of these will work:
var_dump(
range(1, 5, 1), // positive integer
range(1, 5, -1), // negative integer
range(1, 5, 2),
range(1, 5, .5), // positive fractional number
range(1, 5, "-0.1") // negative fractional number passed as string
);
Also, if you use a float value as $step, all the values will be float too, even if they are whole numbers.

Related

Advancing index keys in an array

I have an array with numerical incrementing keys starting at 0, like 0 1 2 3 4 5 ....etc. I need to assign new keys to the array in the following manner
The first three keys keep their index number
Every 4th key gets incremented by 4
The two keys after the fourth gets incremented by 1again
I know I need to use a foreach loop ( seems the simplest way anyway ) to build a new array with newly assigned keys. My problem is the calculation of the keys
HERE IS WHAT I HAVE SEEN IN RELATION
Here is my current array keys
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
and this is what I need them to be
0 1 2 6 7 8 12 13 14 18 19 20 24 25 26 30
Lets break this down into 3 key groups with the old array key on the top and the new array key at the bottom
1st group
0 1 2
0 1 2
2nd group
3 4 5
6 7 8
3rd group
6 7 8
12 13 14
4th group
9 10 11
18 19 20
etc etc......
When you look at the relationship between the two array keys, you'll see the following:
The old array keys 0, 1 and 2 keep their key value
The old array keys 3, 6, 9 etc, if multiplied by 2, gives you the new array key value
The old array keys 4, 7, 10 etc, if multiplied by 2 and you subtract 1 from that total, you get the new array key for that specific key
The old array keys 5, 8, 11 etc, if multiplied by 2 and you subtract 2 from the total, you get the new array key for that specific key
Alternatively, if you subtract the old key from the new key, you get the following answer
0 for the 1st group
3 for the 2nd group
6 for the 3rd group
9 for the 4th group
etc etc.....
POSSIBLE SOLUTION
The only solution I can think of is to use the modulus operator (inside my foreach loop), check the current key against the modulus result and then calculate my new key
Example:
if ( $key%3 == 0 && $key != 0 ) {
$new_key = $key * 2;
} elseif ( ( $key - 1 ) %3 == 0 && $key != 1 ) {
$new_key = ( $key * 2 ) - 1;
} elseif ( ( $key - 2 ) %3 == 0 && $key != 2 ) {
$new_key = ( $key * 2 ) - 2;
} else {
$new_key = $key;
}
$new_array[$new_key] = $value;
MY QUESTION
Isn't there a smarter more mathematical way of doing this?
Try the following:
$new_key = floor($old_key / 3) * 3 + $old_key
If you use modulous you can generate a sequence with items missing. The below code demonstrates how to do that.
for ($x = 0; $x < 40; $x++)
{
echo ("$x, " . ($x % 6) . ", " . ($x % 6 < 3? "true": "false") . "\n");
}
The output is:
0, 0, true
1, 1, true
2, 2, true
3, 3, false
4, 4, false
5, 5, false
6, 0, true
7, 1, true
8, 2, true
9, 3, false
10, 4, false
11, 5, false
12, 0, true
13, 1, true
14, 2, true
15, 3, false
16, 4, false
17, 5, false
18, 0, true
19, 1, true
20, 2, true
21, 3, false
22, 4, false
23, 5, false
24, 0, true
25, 1, true
26, 2, true
27, 3, false
28, 4, false
29, 5, false
30, 0, true
31, 1, true
32, 2, true
33, 3, false
34, 4, false
35, 5, false
36, 0, true
37, 1, true
38, 2, true
39, 3, false
If you use $x as a key only when $x % 6 < 3 you can get the sequence you want.
$array = range(1,15);
For ($i=0; $i<count($array); $i++) echo $keys[] = $i + floor($i/3)*3;
$new_array = array_combine($keys, $array);
var_dump($new_array);

PHP array key to value mappings question

I just saw this on php.net description of how key to value mapping works:
$switching = array( 10, // key = 0
5 => 6,
3 => 7,
'a' => 4,
11, // key = 6 (maximum of integer-indices was 5)
'8' => 2, // key = 8 (integer!)
'02' => 77, // key = '02'
0 => 12 // the value 10 will be overwritten by 12
);
I just cant quite understand how 11 could be assigned key 6. I know 5 is not possible since it is already used on the second element as a key so it makes sense to jump it over.
But should not be 11 intuitively assigned key 4 in the first place since the first element of the array 10 is assigned key 0 and therefore the key value is incremented 0..1..2..3..4 from that point according to the first index unless specified otherwise (e.g 5=>6 could have had key 1, 3=>7 with key 2, and 'a'=> 4 could have had key 3 if not specified)? And also, why does it say that 11 should be assigned a key that represents the maximum integer of indices (in this case 6 since 5 was used already)?
Would appreciate any help/clarification. Please let me know if the question needs to be clarified. Thanks much.
It is implemented in this way just because it is the most performant solution - to just use maximum_specified_key + 1, rather than to find a hole in enumration
I believe it has to do with the way that PHP arrays work. Each has an internal cursor for the each, current, next, pos and similar methods. My guess: as a new key is specified, if it is higher than the current cursor, the cursor is advanced to that position so that anything added after that point will still be at current position + 1.
And also, why does it say that 11
should be assigned a key that
represents the maximum integer of
indices (in this case 6 since 5 was
used already)?
Why not? As zerkms says, it's performant, so there's that.
It's also more or less what you might expect. Given an array with mixed keys like that, what would you expect array_push() to do?
Of course, if you're running into this kind of thing in real life, it's probably time to stop and consider some amount of refactoring. Arrays in PHP are very flexible, and these somewhat arbitrary decisions had to be made. They're documented. The only alternative is to make array usage much more rigid.
The PHP manual gives you the answer in the link you provided:
As mentioned above, if no key is specified, the maximum of the
existing integer indices is taken, and the new key will be that
maximum value plus 1 (but at least 0). If no integer indices exist
yet, the key will be 0 (zero).
The code:
$switching = array( 10, // key = 0
5 => 6,
3 => 7,
'a' => 4,
11, // key = 6 (maximum of integer-indices was 5)
'8' => 2, // key = 8 (integer!)
'02' => 77, // key = '02'
0 => 12 // the value 10 will be overwritten by 12
);
So far the maximum key when you get to 'a' is 5 so the next available key according to the php manual would be 5 + 1 i.e. 6.
Note that the maximum integer key used
for this need not currently exist in the array. It need only have
existed in the array at some time since the last time the array was
re-indexed.
// empty the array;
foreach( $switching as $key => $value ) {
unset( $switching[$key] );
}
// refill it with new elements
for( $i = 0; $i < 10; $i++ ) {
$switching[] = $i + 1;
}
output array:
Array
(
[9] => 1
[10] => 2
[11] => 3
[12] => 4
[13] => 5
[14] => 6
[15] => 7
[16] => 8
[17] => 9
[18] => 10
)

php importance of a number in a set of numbers

I have a set of numbers e.g.
$input = array(1, 4, 7, 4, 9, 4, 8, 6, 2, 8, 7, 7, 4, 5, 3);
I am trying to work out the importance of each number based on the following rule:
As the sequence gets longer the numbers get less significant, and each time a number is mentioned then it will improve the relevance (how much depends on its position in the
sequence).
I am expecting something like:
Array(
'4' => 90%
'1' => 75%
'7' => 60%
....
)
So 4 is the most inportant, followed by 1 and then 7 etc. Note that the output is completely fabricated but gives in indication that 4 should be the most important. I believe I want some kind of linear solution.
Is this more of what you were thinking? Answer based on stillstanding
$numbers = array(1, 4, 7, 4, 9, 4, 8, 6, 2, 8, 7, 7, 4, 5, 3);
$weight = array();
$count = count($numbers);
for ($i=0; $i<$count; $i++) {
if (!isset($weight[$numbers[$i]])) $weight[$numbers[$i]] = 1;
$weight[$numbers[$i]] += $count + pow($count - $i, 2);
}
$max = array_sum($weight);
foreach ($weight as &$w) {
$w = ($w / $max) * 100;
}
arsort($weight);
result:
Array
(
[4] => 34.5997286296
[7] => 17.3677069199
[1] => 16.3500678426
[8] => 10.0407055631
[9] => 9.29443690638
[6] => 5.42740841248
[2] => 4.40976933514
[5] => 1.35685210312
[3] => 1.15332428765
)
$numbers=array(1, 4, 7, 4, 9, 4, 8, 6, 2, 8, 7, 7, 4, 5, 3);
$weight=array();
$count=count($numbers);
for ($i=0; $i<$count; $i++) {
if (!isset($weight[$numbers[$i]]))
$weight[$numbers[$i]]=1;
$weight[$numbers[$i]]*=$count-$i;
}
var_dump($weight);
Result:
Array
(
[1] => 15
[4] => 5040
[7] => 260
[9] => 11
[8] => 54
[6] => 8
[2] => 7
[5] => 2
[3] => 1
)
This algorithm is fairly simplistic, but I think it accomplishes what you're looking for.
Given that you have the sequence you described above and it is stored in an array called $sequence
$a = array();
for($i=0;$i<count($sequence);$i++)
{
//calculate the relevance = 1/position in array
$relevance = 1/($i+1);
//add $relevance to the value of $a[$sequence[$i]]
if(array_key_exists((string)$sequence[$i],$a))
$a[(string)$sequence[$i]] += $relevance;
else
$a[(string)$sequence[$i]] = $relevance;
}
return $a;

How to remove integers in array less than X?

I have an array with integers of values from 0 to 100. I wish to remove integers that are less than number X and keep the ones that are equal or greater than number X.
A little ugly using the clunky create_function, but straight forward:
$filtered = array_filter($array, create_function('$x', 'return $x >= $y;'));
For PHP >= 5.3:
$filtered = array_filter($array, function ($x) { return $x >= $y; });
Set $y to whatever you want.
Smarter than generating an array that is too big then cutting it down to size, I recommend only generating exactly what you want from the very start.
range() will do this job for you without the bother of an anonymous function call iterating a condition.
Code: (Demo)
$rand=rand(0,100); // This is your X randomly generated
echo $rand,"\n";
$array=range($rand,100); // generate an array with elements from X to 100 (inclusive)
var_export($array);
Potential Output:
98
array (
0 => 98,
1 => 99,
2 => 100,
)
Alternatively, if you truly, truly want to modify the input array that you have already generated, then assuming you have an indexed array you can use array_slice() to remove elements using X to target the starting offset and optionally preserve the indexes/keys.
Code: (Demo)
$array=range(0,100);
$rand=rand(0,100); // This is your X randomly generated
echo $rand,"\n";
var_export(array_slice($array,$rand)); // reindex the output array
echo "\n";
var_export(array_slice($array,$rand,NULL,true)); // preserve original indexes
Potential Output:
95
array (
0 => 95,
1 => 96,
2 => 97,
3 => 98,
4 => 99,
5 => 100,
)
array (
95 => 95,
96 => 96,
97 => 97,
98 => 98,
99 => 99,
100 => 100,
)

Autogenerate array values with a loop?

I know this doesn't work but is there any way of autogenerating values? It can be pretty tedious to put so many values in specially if it's 50 or maybe 100 numbers...
Here's the code so you get my idea:
for ($num = 1; $num <= 20; $num++){
$arr = array($num);
echo $arr[2];
};
Solved: It was the range() and arrayfill(). :)
Take a look at the range() function.
>> $a = range(1, 10);
array (
0 => 1,
1 => 2,
2 => 3,
3 => 4,
4 => 5,
5 => 6,
6 => 7,
7 => 8,
8 => 9,
9 => 10,
)
>>
Or maybe array_fill()?
Are you talking about the rand() function? That surely exist ;)
PHP Rand Function

Categories