Generate equal set of number minus to plus with PHP - php

i need help to create set of numbers below with PHP.
example:
$i = 7
result:
-3,-2,-1,0,1,2,3
Another example:
$i = 3
result:
-1,0,1
Thanks

You can use range, with minimum/maximum values of +/-floor($i/2) e.g.
$i = 7;
print_r(range(-floor($i / 2), floor($i / 2)));
Output:
Array
(
[0] => -3
[1] => -2
[2] => -1
[3] => 0
[4] => 1
[5] => 2
[6] => 3
)
If you want it to work with even numbers, you have to decide whether you want the range to have more negative values or positive values, and adjust the min/max accordingly:
$i = 4;
print_r(range(-floor($i / 2), floor($i / 2) - 1));
$i = 4;
print_r(range(1 - floor($i / 2), floor($i / 2)));
Output:
Array
(
[0] => -2
[1] => -1
[2] => 0
[3] => 1
)
Array
(
[0] => -1
[1] => 0
[2] => 1
[3] => 2
)
Demo on 3v4l.org
Once you decide which direction you prefer to have more values if the input is even, you can make the code work for even & odd values by using % to determine if the input is odd or even. For more negative values:
print_r(range(-floor($i / 2), floor($i / 2) - ($i + 1) % 2));
For more positive values:
print_r(range(($i + 1) % 2 - floor($i / 2), floor($i / 2)));
Demo on 3v4l.org

Related

Php - get number, not char from string

I'm not very familiar with php and got stuck in how to use substr in this case:
I have to do the parse of a string that has some numbers and symbols,
example:
1[2[3,5],4[7[65,9,11],8]]
And to do this I used a for that will go through and get each char of the string,
something like that:
$count = 0;
for($i = 0; $i <= strlen($string); $i++){
$char = substr($string, $i, 1);
if($char == '['){
$count --;
}
if($char == ']'){
$count ++;
}
if($count == 0){
break;
}
if(is_numeric(substr($string, $i +1, 1)) and $count == -1){
$number = substr($string, $i +1, 1);
$array_aux[] = $number;
}
}
But as I'm getting the char in (substr ($ string, $ i, 1)) it does not work for numbers with more than one digit, such as 65 and 11
And the contents of the array gets something like: (..., 6, 5, 9, 1, 1, ...)
When should be something like: (..., 65, 9, 11, ...)
Any help?
Sorry, I think was not clear enough.
I need the numbers that are inside '[' when count has the value -1
(that's why I'm using substr, and taking every char)
examples: when the string is: 1[2[3,5],4[7[65,9,11],8]], the array must contain 2 and 4
when the string is: 2[3,5],4[7[65,9,11],8]], the array must contain 3 and 5
when the string is: 7[65,9,11],8]], the array must contain 65, 9 and 11. And so on...
Sorry to put these details only now, I was without computer :(
preg_match_all with a simple regular expression can do this for you:
$in = "1[2[3,5],4[7[65,9,11],8]]";
preg_match_all('~\d+~', $in, $out);
print_r($out[0]);
Outputs:
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 5
[4] => 4
[5] => 7
[6] => 65
[7] => 9
[8] => 11
[9] => 8
)
You can use preg_split and split by matching one or more times not a digit \D+
$str = "1[2[3,5],4[7[65,9,11],8]]";
print_r(preg_split("/\D+/", $str, -1, PREG_SPLIT_NO_EMPTY));
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 5
[4] => 4
[5] => 7
[6] => 65
[7] => 9
[8] => 11
[9] => 8
)

Why is range() not inclusive when given with float range and interval?

The documentation states that the $end of the range is inclusive. And this is the case most of the time, but when both $end and $step are floats, the last value is missing. Why is that?
print_r(range(1, 13, 1));
print_r(range(1, 13, 0.1));
print_r(range(0.1, 1.3, 0.1));
Output:
Array
(
[0] => 1
[1] => 2
// ...
[11] => 12
[12] => 13
)
Array
(
[0] => 0.1
[1] => 0.2
// ...
[119] => 12.9
[120] => 13
)
Array
(
[0] => 0.1
[1] => 0.2
// ...
[10] => 1.1
[11] => 1.2
// 12 => 1.3 is missing
)
The range is inclusive; however, your assumptions about the numbers adding up are incorrect.
0.1 cannot be represented in binary with exact precision. When you use it in a calculation in php, you'll actually get a number that's a little higher or lower. Take a look at the following codepad:
http://codepad.org/MkoWgAA1
<?php
$sum = 1.0 + 0.1 + 0.1;
if ($sum > 1.2) {
print("1.2 > 1.2");
} else if ($sum < 1.2) {
print("1.2 < 1.2");
} else {
print("1.2 == 1.2");
}
Output:
1.2 > 1.2

Getting week numbers for last X weeks

I have a script that builds an array of week numbers for the last 12 weeks like so:
$week_numbers = range(date('W'), date('W')-11, -1);
However, if the current week number is 1, then this will return an array like so:
Array
(
[0] => 1
[1] => 0
[2] => -1
[3] => -2
[4] => -3
[5] => -4
[6] => -5
[7] => -6
[8] => -7
[9] => -8
[10] => -9
[11] => -10
)
But I need this array to look like this instead:
Array
(
[0] => 1
[1] => 52
[2] => 51
[3] => 50
[4] => 49
[5] => 48
[6] => 47
[7] => 46
[8] => 45
[9] => 44
[10] => 43
[11] => 42
)
Can anyone see a simple solution to this?
I have thought about doing something like this (not tested):
$current_week_number = date('W');
if($current_week_number<12){
// Calculate the first range of week numbers (for current year)
$this_year_week_numbers = range(date('W'), 1, -1);
// Calculate the next range of week numbers (for last year)
$last_year_week_numbers = range(52, 52-(11-$current_week_number), -1);
// Combine the two arrays to return the week numbers for the last 12 weeks
$week_numbers = array_merge($this_year_week_numbers,$last_year_week_numbers);
}else{
// Calculate the week numbers the easy way
$week_numbers = range(date('W'), date('W')-11, -1);
}
one idea
$i = 1;
while ($i <= 11) {
echo date('W', strtotime("-$i week")); //1 week ago
$i++;
}
if you arent scared of loops you can do this:
$week_numbers = range(date('W'), date('W')-11, -1);
foreach($week_numbers as $key => $value) { if($value < 1) $week_numbers[$key] += 52; }
You can do a modulo % trick:
$week_numbers = range(date('W'), date('W')-11, -1);
foreach ($week_numbers as $i => $number) {
$week_numbers[$i] = (($week_numbers[$i] + 52 - 1) % 52) + 1;
}
// -1 +1 is to change the range from 0-51 to 1-52
I've found that using modulo like this is often useful for date calculations, you can something similar for months, using 12.
Well, I think the easiest way is to create array after getting dates:
$week_numbers = array_map(function($iDay)
{
return ($iDay+52)%52?($iDay+52)%52:52;
}, range(date('W'), date('W')-11));
-note, that you can not do just % since 52%52 will be 0 (and you want 52)

Sorting a multidimensional array for ranking using PHP in CodeIgniter?

I'm looking to use the results in an array and sort them using a ranking algorithm similar to say Hacker News or Reddit.
For example, paraphrasing the HN algorithm:
Score = P / (T+2)^G
where,
P = points of an item (e.g. votes + comments + likes)
T = time since submission (in hours)
G = Gravity, (on HN defaults to 1.8)
From what I understand, I need to use a PHP sorting array, but the PHP manual is confusing, and the similar answers on StackOverflow have very specific answers without many comments as to what the function is doing. e.g. here, here & here.
My data looks as follows
Array
(
[0] => Array
(
[post_created] => 2011-12-12 07:18:17
[post_num_likes] => 1
[post_num_comments] => 0
[post_message] => Some message
[votes] => 16
)
[1] => Array
(
[post_created] => 2011-12-11 22:17:16
[post_num_likes] => 0
[post_num_comments] => 4
[post_message] => Another message
[votes] => 21
)
[2] => Array
(
[post_created] => 2011-12-11 20:21:11
[post_num_likes] => 1
[post_num_comments] => 2
[post_message] => Next message
[votes] => 1
)
[3] => Array
(
[post_created] => 2011-12-11 20:11:47
[post_num_likes] => 0
[post_num_comments] => 0
[post_message] => Something else
[votes] => 0
)
[4] => Array
(
[post_created] => 2011-12-11 20:09:46
[post_num_likes] => 1
[post_num_comments] => 0
[post_message] => Another message
[votes] => 5
)
So far as I understand, I need to do something like the following:
// Send array as 2nd parameter due to way you call functions in CodeIgniter
uksort($array, array('Class_name','postrank'));
function postrank($a, $b) {
// some sorting function here
return strcmp($a, $b);
}
I've tried copying and pasting various functions, but as they're not so well commented, it's hard to know what's going on.
How might I go about recreating a similar post ranking sorting function with the above data?
amidoinitrite?
SELECT * , (
votes + post_num_comments + post_num_likes - 1
) / POW( ROUND( (
TIME_TO_SEC( TIMEDIFF( NOW( ) , post_created ) ) / 3600 ) + 2 ) , 1.8
) AS score
FROM hacker_news
ORDER BY score DESC
The formula on website is actually: Score = (P-1) / (T+2) ^ G
My example code for PHP older than 5.3 :)
<?php
function customSort($a, $b){
foreach(array('a', 'b') as $vn){
$tmp = $$vn;
$p = $tmp['post_num_likes'] + $tmp['post_num_comments'] + $tmp['votes'];
$t = ceil((time() - strtotime($tmp['post_created'])) / 3600);
$$vn = $p / pow($t + 2, 1.81);
}
return $a - $b;
}
usort($array, 'customSort');
var_dump($array);
$score = function($arr) {
extract($arr);
return ($votes + $comments + $likes) / pow($created_time + 2, 1.8);
};
usort($array, function($a, $b) use ($score) {
return $score($a) - $score($b);
});
This needs php 5.3 because I used anonymous functions.

Evenly distributed integers within a range

Lets say I have a range between 0 and 100 and I want an array returned containing 3 integers which are evenly distributed within that range, what would be the best way to do this?
For example:
Range: 0-100
Wanted: 3
Returned: 25, 50, 75
Pseudo code:
function distributeIntegers(int wanted, int rangeLow, int rangeHigh)
int increment = (rangeHigh - rangeLow) / (wanted + 1)
array r = new array()
for (int i = rangeLow + increment; i < rangeHigh; i += increment)
r.push(i)
return r
PHP:
function distributeIntegers($wanted = 3, $rangeLow = 0, $rangeHigh = 100){
$increment = ($rangeHigh - $rangeLow) / ($wanted + 1);
$r = array();
for ($i = $rangeLow + $increment; $i < $rangeHigh; $i += $increment)
$r []= $i;
return $r;
}
/*
examples:
call:
distributeIntegers();
returns:
[0] => 25
[1] => 50
[2] => 75
call:
distributeIntegers(4);
returns:
[0] => 20
[1] => 40
[2] => 60
[3] => 80
call:
distributeIntegers(5, 50, 200);
returns:
[0] => 75
[1] => 100
[2] => 125
[3] => 150
[4] => 175
*/
you can make use of array_chunk(), eg only
$end=100;
$a = range(0,$end);
$chunk=3;
foreach (array_chunk($a,$end/($chunk+1)) as $s){
print $s[0]."\n";
}
output
$ php test.php
0
25
50
75
100
you can get rid of the start (0) and end(100) points if not needed.
Here's a solution in groovy that gives the answers you want, you should be able to switch it to whatever language you're using:
def distributedValues(min, max, wanted) {
def incrementBy = (max - min)/(wanted + 1)
(1..wanted).collect { count -> min + (count * incrementBy) }
}
assert distributedValues(0, 100, 1) == [50]
assert distributedValues(0, 100, 3) == [25, 50, 75]
assert distributedValues(0, 100, 4) == [20, 40, 60, 80]
assert distributedValues(0, 100, 5) == [16.6666666667, 33.3333333334, 50.0000000001, 66.6666666668, 83.3333333335]
assert distributedValues(100, 200, 3) == [125, 150, 175]
You can use the rand function to get the random value between the specific ranges.
Use this code . This following function would return set of element in a array
function array_elements( $start = 0 , $end = 100 , $element =5 )
{
$myarray = array () ;
for ( $i = 0 ; $i < $element;$i++ )
{
$myarray[$i]= rand ( $start, $end );
}
return $myarray ;
}
print_r ( array_elements() ) ;

Categories