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
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
)
)
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
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;
}
//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.
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'";
Related
I have a problem trying using for loop inside a loop i can't get the result i want
<?php
for($sg = 1; $sg <= 11; $sg++){
echo "<b>".echo $sg;."</b>";
for($g = 1; $g <= 11; $g++){
echo "<p>".echo $g."</p>";
}
?>
I looking the result to be like
1
1 2 3 4 5 6 7 8 9 10 11
2
12 13 14 15 16 17 18 19 20
3
21 22 23 24 25 26 27 28 29 30
continuous ....
<?php
for($sg = 1; $sg <= 11; $sg++){
echo "<br /> <b>". $sg."</b> ";
for($g = 1+(10*($sg-1)); $g <= (10*($sg-1))+10; $g++){
echo "". $g." ";
}
}
?>
Output:
1 1 2 3 4 5 6 7 8 9 10
2 11 12 13 14 15 16 17 18 19 20
3 21 22 23 24 25 26 27 28 29 30
4 31 32 33 34 35 36 37 38 39 40
5 41 42 43 44 45 46 47 48 49 50
6 51 52 53 54 55 56 57 58 59 60
7 61 62 63 64 65 66 67 68 69 70
8 71 72 73 74 75 76 77 78 79 80
9 81 82 83 84 85 86 87 88 89 90
10 91 92 93 94 95 96 97 98 99 100
11 101 102 103 104 105 106 107 108 109 110
<?php
$inner_start = 1;
$inner_max = 11;
for($sg = 1; $sg <= 11; $sg++){
echo "<b>".$sg."</b></br>";
echo "<p>";
for($g = $inner_start; $g <= $inner_max; $g++){
echo $g . ' ';
}
$inner_start = $inner_start + 10;
$inner_max += 10;
echo "</p></br>";
}
?>
I am using simple pagination with following code.
But I want to show 1 2 3 ..... 10 11 12 type pagination.
When more number of pages are there, pagination should be adjusted accordingly.
My current simple pagination php code is :
<?php
if (isset($_GET["start"])){
$start = $db->filter($_GET["start"]);
}
if(empty($start)){
$start= 0;
}
$maxrecords = 10;
$pagination_query = "select * from table order by id desc";
$pagination_count = $db->num_rows($pagination_query);
$query = "select * from table order by id desc limit $start,$maxrecords"; // For record to display...
$result = $db->get_results($query);
?>
<div class="pagination">
<?php
for($i=0;$i<ceil($pagination_count/$maxrecords);$i++){
if($start==$i*$maxrecords){
?>
<a class='active'> <?php print $i+1;?></a>
<?php }else{ ?>
<?php print $i+1;?>
<?php
}
}
?>
</div>
<!-- Rest code to display records goes here -->
Now this code is working rightly...
Only thing is it is showing paginatin - 1 2 3 4 5 6 7 like unlimited depending upon total records in database...
I want to convert it to 1 2 3 .... 22 23 24 etc...
Your valuable help appreciated...
My answer begins by some notes about what I'm seeing about pagers.
Then, this answer doesn't provide the "expected result" you want, but I think it could be more "flexible".
I think your query to get the number of record seems to be expensive. You could just use a count(*) :
$pagination_query = "select count(*) as num from table order by id desc" ;
$pagination_count = $db->get_field_result() ; // I don't know your DB API.
I think your query to get the current results seems to doesn't take care about the $start and $maxrecords (but I don't known your database API) :
$query = "select * from table order by id desc limit ".($start*$maxrecords).",$maxrecords"; // range 0+10, 10+10, 20+10, ...
You could use several loops to display begining pages, "around current", and ending pages.
Here is a "sample" code, not perfect, but it could helps you to imaging your own pager.
$start = 7 ; // try with 1, 7, 24, 75...
$pagination_count = 40 ; // Number of results
$maxrecords = 10 ;
$num_pages = ceil($pagination_count / $maxrecords) ;
// echo "num_pages=$num_pages\n" ; // Just for dev
if ($start > $num_pages) { $start = $num_pages; }
if ($num_pages < 6) {
for ($i = 0; $i < $num_pages ; $i++) {
echo render_page_link($i, $start);
}
}
else {
// Begining
for ($i = 0 ; $i < min(3, $num_pages); $i++) {
echo render_page_link($i,$start) ;
}
echo ' (...) ' ;
$have_middle = ($start > 3 && $start <= $num_pages - 3) ;
if ($have_middle) {
// Around current
for ($i = max(3, $start - 3); $i < min($start + 3 - 1, $num_pages - 3) ; $i++) {
echo render_page_link($i,$start) ;
}
}
// Ending
if ($have_middle) echo ' (...) ' ;
for ($i = $num_pages - 3; $i < $num_pages ; $i++) {
echo render_page_link($i,$start);
}
}
echo "\n"; // just because I test on CLI.
// Here is a little function to display the link:
// Currently just "plain text", but could be <a> or <span> with CSS...
function render_page_link($index, $current = -1)
{
if ($index != $current - 1) return ($index+1) . " " ;
return "[".($index+1)."] " ;
}
Example result for 1 to 24 pages
[1] 2 3 (...) 22 23 24
1 [2] 3 (...) 22 23 24
1 2 [3] (...) 22 23 24
1 2 3 (...) [4] 5 6 (...) 22 23 24
1 2 3 (...) 4 [5] 6 7 (...) 22 23 24
1 2 3 (...) 4 5 [6] 7 8 (...) 22 23 24
1 2 3 (...) 5 6 [7] 8 9 (...) 22 23 24
1 2 3 (...) 6 7 [8] 9 10 (...) 22 23 24
1 2 3 (...) 7 8 [9] 10 11 (...) 22 23 24
1 2 3 (...) 8 9 [10] 11 12 (...) 22 23 24
1 2 3 (...) 9 10 [11] 12 13 (...) 22 23 24
1 2 3 (...) 10 11 [12] 13 14 (...) 22 23 24
1 2 3 (...) 11 12 [13] 14 15 (...) 22 23 24
1 2 3 (...) 12 13 [14] 15 16 (...) 22 23 24
1 2 3 (...) 13 14 [15] 16 17 (...) 22 23 24
1 2 3 (...) 14 15 [16] 17 18 (...) 22 23 24
1 2 3 (...) 15 16 [17] 18 19 (...) 22 23 24
1 2 3 (...) 16 17 [18] 19 20 (...) 22 23 24
1 2 3 (...) 17 18 [19] 20 21 (...) 22 23 24
1 2 3 (...) 18 19 [20] 21 (...) 22 23 24
1 2 3 (...) 19 20 [21] (...) 22 23 24
1 2 3 (...) [22] 23 24
1 2 3 (...) 22 [23] 24
1 2 3 (...) 22 23 [24]
I have to make this kind of structure in array;
We have three ( 3 ) variables which creates this structure:
$numberOfParticipants = 38; // 38 is example
$numberOfParticipantsPerHeat = 8 // 8 is example
$numberOfHeats = 5; // 5 is example
Based on this variables I have this table:
The problem is that, I can't place the ' - ' or null after 31 OR 38. The task is that i have to make the arrays of array "almost equal" like the photo and must depend on the variables above. By the way, after I create the correct list I will slice the array to 5 or 6 or whatever parts I need this is not the problem, the problem is that I have to parse the list like this first. This is what I tried so far:
$calc1 = (int)round($numberOfParticipants * $numberOfParticipantsPerHeat, -1); //First round the numberOfParticipants to closest integer by 10
$readyArr = [];
for ($i = 1; $i <= $calc1; $i++) {
if ($i <= $numberOfParticipants) {
$readyArr[$i] = $i;
} else {
$readyArr[$i] = null;
}
}
The problem with this snippet is that it places the null at the end of the list not after 31, or based on the var.
This is the result I have:
array:40 [▼
1 => 1
2 => 2
3 => 3
4 => 4
5 => 5
6 => 6
7 => 7
8 => 8
9 => 9
10 => 10
11 => 11
12 => 12
13 => 13
14 => 14
15 => 15
16 => 16
17 => 17
18 => 18
19 => 19
20 => 20
21 => 21
22 => 22
23 => 23
24 => 24
25 => 25
26 => 26
27 => 27
28 => 28
29 => 29
30 => 30
31 => 31
32 => 32
33 => 33
34 => 34
35 => 35
36 => 36
37 => 37
38 => 38
39 => null
40 => null
]
The Array after partition I want should be:
array(
0 => array(0 => 1, 1 => 2, 2 => 3, 3 => 4, 4 => 5, 5 => 6, 6 => 7, 7 => 8,),
1 => array(0 => 9, 1 => 10, 2 => 11, 3 => 12, 4 => 13, 5 => 14, 6 => 15, 7 => 16,),
2 => array(0 => 17, 1 => 18, 2 => 19, 3 => 20, 4 => 21, 5 => 22, 6 => 23, 7 => 24,),
3 => array(0 => 25, 1 => 26, 2 => 27, 3 => 28, 4 => 29, 5 => 30, 6 => 31, 7 => null,),
4 => array(0 => 32, 1 => 33, 2 => 34, 3 => 35, 4 => 36, 5 => 37, 6 => 38, 7 => null,),
);
Every help, every clue will be highly appreciated.
There are two things you need to know about the target structure:
How many players are in the first (which will always be the largest, if only by one) set.
$playersPerHeat = ceil($numberOfParticipants / $numberOfHeats);
// note this replaces your hard-coded $numberOfParticipantsPerHeat
You also need to know how many heats actually have that many, that is how many heats are actually full.
$fullHeats = $numberOfParticipants % $numberOfHeats ?: $numberOfHeats;
// The ?: bit means that if we get zero (ie. all equal heats), then we
// count all the heats instead, since they're all full.
Now it's easy!
$players = range(1,$numberOfParticipants);
$heats = array_merge(
array_chunk(
array_slice($players, 0, $fullHeats * $playersPerHeat),
$playersPerHeat
),
array_chunk(
array_slice($players, $fullHeats * $playersPerHeat),
$playersPerHeat - 1
)
);
That's it! Demo
Each number has a corresponding value with it. There are many numbers which I can demonstate in a table here with their appropriate values:
[N] [V] N=Number V=Value
2 19
4 19
6 19
8 21
10 21
12 22
14 23
16 23
18 23
20 33
22 37
24 42
26 45
28 48
30 50
32 55
34 61
36 66
38 72
40 78
42 155
44 179
46 202
48 233
50 360
There is a process that a user will go through where they go from Number x to Number y. The values inbetween those numbers need to get added together. So for example, let's say a user goes from 16 to 38:
[N] [V] N=Number V=Value
2 19
4 19
6 19
8 21
10 21
12 22
14 23
[16][23]--
18 23 |
20 33 |
22 37 |
24 42 |
26 45 |
28 48 |---- All of these values get added together
30 50 |
32 55 |
34 61 |
36 66 |
[38][72]--
40 78
42 155
44 179
46 202
48 233
50 360
So the users total value would equal be:
23 + 23 + 33 + 37 + 42 + 45 + 48 + 50 + 55 + 61 + 66 + 72
Total Value = 555
The problem is, is that I have no idea how I to put this together in code. Like how to assign these values to their specific number and how to add those specific values together to get me a result. In PHP I simply do not know where to begin with this.
Also, the approximate values from the numbers can be represented by this equation:
v = 11.218e^(0.057n)
I would imagine this would be useful in making this whole process easier but I am still not sure how to go about implementing all of this. Any help would be very much apprieciated!
Put each each number with it's corresponding value into an array making number as key and value pair like this.
<?php
$arr = array(
2=> 19,
4=> 19,
6=> 19,
8=> 21,
10=> 21,
12=> 22,
14=> 23,
16=> 23,
18=> 23,
20=> 33,
22=> 37,
24=> 42,
26=> 45,
28=> 48,
30=> 50,
32=> 55,
34=> 61,
36=> 66,
38=> 72,
40=> 78,
42=> 155,
44=> 179,
46=> 202,
48=> 233,
50=> 360,
);
?>
Loop array with foreach loop like this
<?php
$sum = 0;
foreach($arr as $k => $v) {
if($k >= 16 && $k <= 38)
$sum += $v;
}
?>
There is another way using for loop statement, put both number in two separate array ($n and $v). Iterate the loop of the first array($n) and find the value from second array($v) through the index number of first array. But both array count should have same.
Example-
<?php
$n = array(2,4,6,8,10,12,14,16,18,20);
$v = array(19,19,19,21,21,22,23,23,23,33);
$sum = 0;
for($i=0, $i<count($n); $i++) {
if($n[$i] >= 16 && $n[$i] <= 38)
$sum += $v[$i];
}
?>
You would put your number and value pairs into an key / value array. So a shortened version of your test data would look like this:
$myDataStore = array(
"2" => "19",
"4" => "19",
"6" => "19",
"8" => "21",
"10" => "21",
"12" => "22",
"14" => "23",
"16" => "23",
"18" => "23",
"20" => "23"
);
Now you need a function to calculate your sum given a range as defined by starting and ending numbers.
function getRangeTotal($array, $startNumber, $endNumber){
$total = 0;
foreach($array as $key => $value){
if($key >= $startNumber && $key <= $endNumber){
$total = $total + $value;
}
}
return $total;
}
If you run the above function
getRangeTotal($myDataStore, 6, 12);
You'll get 83
Here is how you can do this using foreach
// first store you data to an array.
$kv = array(
2 => 19, 4 => 19, 6 => 19, 8 => 21,
10 => 21, 12 => 22, 14 => 23, 16 => 23,
18 => 23, 20 => 33, 22 => 37, 24 => 42,
26 => 45, 28 => 48, 30 => 50, 32 => 55,
34 => 61, 36 => 66, 38 => 72, 40 => 78,
42 => 155, 44 => 179, 46 => 202,48 => 233,
50 => 360
);
$start = 16;
$end = 32;
$sum = 0; //variable to keep sum
$n = 0; //variable to keep count
//loop through the array
foreach ($kv as $k => $v){
if ($k >=$start && $k <= $end){ //if key is in your range
$sum += $v; //add value to sum
$n ++; // increment count
}
}
$v = 11.218*pow(M_E,0.057*$n); //calculate the approximate values
echo "$sum\n$v\n";
Also refer to : pow and Predefined Constants
I have $amounts eg. 31; 48; 57; 63; 79; 84 and 95
What I would like to do is loop through each “$amount”, and if they are above 50, create variable that adds 1 for each 10 increment
Eg.
$amount(57) = +1
$amount(63) = +2
$amount(79) = +3
$amount(84) = +4
$amount(95) = +5
UPDATED VERSION:
Apologies for the vague question.
I have
$amount = array(end($percentage));
eg. 47, 63, 79, 95
What I would like to have is another variable to be created eg. $to_add if $amount > 50.
Then for each $amount >= 50 add 1 to the $to_add
Should look like:
$amount(47) = NULL ($to_add = 0)
$amount(50) = $to_add = 1 – *WOULD HAVE BEEN*
$amount(63) = $to_add = 2
$amount(79) = $to_add = 3
$amount(80) = $to_add = 4 – *WOULD HAVE BEEN*
$amount(95) = $to_add = 5
Thanks for the input thus far - I am testing the feedback I have already received - thank you very much!
This should work for you:
(Here I just go through each element with array_map(), then I check if the value is over 50 and if yes I add 1 for every 10)
<?php
$amount = [31, 48, 57, 63, 79, 84, 95];
print_r($amount);
$amount = array_map(function($v){
if($v / 50 >= 1)
return ceil($v + ($v-50)/10);
return $v;
}, $amount);
print_r($amount);
?>
output:
Array ( [0] => 31 [1] => 48 [2] => 57 [3] => 63 [4] => 79 [5] => 84 [6] => 95 )
Array ( [0] => 31 [1] => 48 [2] => 58 [3] => 65 [4] => 82 [5] => 88 [6] => 100 )
Somewhat like this:
$array=array();
$i=0;
foreach($amounts as $amount){
if($amount>50){
$value=floor($amount/10);
$array[$i]=$value;
$i++;
}
}
var_dump($array);
Now $array contains the values you want. You have to adapt the code to your code since I have no idea what $amount is(I assume values of an array)