Convert Excel table to 2d array - php

I have next Excel table with date in first column and some data in others (B, C).
1.
2.
And I want to transform it to table like on pic 3:
To do this you need to add up the data from each row and column within an hour (don't know how to say it right) and multiply by 2400.
For example, from first picture we have (0.0022 + 0.0078 + 0.0021 + 0.0078) * 2400 ≈ 47 — first element of the table from third picture.
I'm trying to do it with PHPExcel library:
$objPHPExcel = new PHPExcel();
$objPHPExcel = PHPExcel_IOFactory::load("data.xlsx");
$highestRow = $objPHPExcel->getActiveSheet()->getHighestRow();
$day = 1;
$hour = 1;
$data = array(array());
for ($i = 1; $i < $highestRow + 1; $i++) {
$cell1 = $objPHPExcel->getActiveSheet()->getCellByColumnAndRow(1, $i)->getValue();
$cell2 = $objPHPExcel->getActiveSheet()->getCellByColumnAndRow(2, $i)->getValue();
$data[$day][$hour] += $cell1 + $cell2;
if($i % 2 == 0) { $data[$day][$hour] *= 2400; $hour++; }
if($i % 48 == 0) $day++;
if($hour % 24 == 0) $hour = 1;
}
But instead of working code I get errors
Line 22:
$data[$day][$hour] += $cell1 + $cell2;
I think that something with my 2D array and as I can see my array keys is bad (not 1-24 for hours).
What should be the code to get my data in 2D array like $data[1..29-31][1-24] or any other? Or may be it is possible to get table from picture #3 some other way?

As your line number 22 is
$data[$day][$hour] += $cell1 + $cell2;
You are trying to increment $data[$day][$hour] which is not even defined yet. You need to define it before trying to increment it. I am not sure, it will make the sheet work like you are expecting. But this will fix the error you are getting. (Add this before line 22)
if(!isset($data[$day])) {
$data[$day] = array(); //Setting the day which will get the hours in array
}
if(!isset($data[$day][$hour])) {
$data[$day][$hour] = 0; //Setting the hours which will contain the incremented values for each hour. Setting it 0, the next code blocks will increment it.
}

Related

Possible combinations of binary

The problem statement is as following:
A particular kind of coding which we will refer to as "MysteryCode" is a binary system of encoding in which two successive values, differ at exactly one bit, i.e. the Hamming Distance between successive entities is 1. This kind of encoding is popularly used in Digital Communication systems for the purpose of error correction.
LetMysteryCodes(N)represent the MysteryCode list for N-bits.
MysteryCodes(1) = 0, 1 (list for 1-bitcodes,in this order)
MysteryCodes(2) = 00, 01, 11, 10 (list for 2-bitcodes,in this order)
MysteryCodes(3) =000, 001, 011, 010,110, 111, 101, 100 (list for 3-bitcodes,in this order)
There is a technique by which the list of (N+1) bitcodescan be generated from (N)-bitcodes.
Take the list of N bitcodesin the given order and call itList-N
Reverse the above list (List-N), and name the new reflected list: Reflected-List-N
Prefix each member of the original list (List-N) with 0 and call this new list 'A'
Prefix each member of the new list (Reflected-List-N) with 1 and call this new list 'B'
The list ofcodeswith N+1 bits is the concatenation of Lists A and B.
A Demonstration of the above steps: Generating the list of 3-bitMysteryCodesfrom 2-BitMysteryCodes
2-bit list ofcodes:00, 01, 11, 10
Reverse/Reflect the above list:10, 11, 01, 00
Prefix Old Entries with 0:000, 001, 011, 010
Prefix Reflected List with 1:110, 111, 101, 100
Concatenate the lists obtained in the last two steps:000, 001, 011, 010, 110, 111, 101, 100
Your Task
Your task is to display the last N "MysteryCodes" from the list of MysteryCodes for N-bits. If possible, try to identify a way in which this list can be generated in a more efficient way, than iterating through all the generation steps mentioned above.
More efficient or optimized solutions will receive higher credit.
Input Format
A single integer N.
Output Format
N lines, each of them with a binary number of N-bits. These are the last N elements in the list ofMysteryCodesfor N-bits.
Input Constraints 1 = N = 65
Sample Input 1
1
Sample Output 1
1
Explanation for Sample 1
Since N = 1, this is the (one) last element in the list ofMysteryCodesof 1-bit length.
Sample Input 2
2
Sample Output 2
11
10
Explanation for Sample 2 Since N = 2, these are the two last elements in the list ofMysteryCodesof 2-bit length.
Sample Input 3
3
Sample Output 3
111
101
100
$listN = 25;
$bits = array('0','1');
//check if input is valid or not
if(!is_int($listN))
{
echo "Input must be numeric!";
}
if($listN >= 1 && $listN <=65){
if($listN == 1){
echo '1'; exit;
}
ini_set('memory_limit', -1);
for($i=1; $i<=($listN - 1); $i++){
$reverseBits = array_reverse($bits);
$prefixBit = preg_filter('/^/', '0', $bits);
$prefixReverseBits = preg_filter('/^/', '1', $reverseBits);
$bits = array_merge($prefixBit, $prefixReverseBits);
unset($prefixBit, $prefixReverseBits, $reverseBits);
}
$finalBits = array_slice($bits, -$listN);
foreach($finalBits as $k=>$v){
echo $v."\n";
}
}
else{
echo "Invalid input!";
}
I have tried above solution, but didnt worked for input greater than 20.
for eg. If the input is 21, I got "Couldnt allocate memory" error.
It will be great if somebody figure out the optimized solutions...
The numbers follow a pattern which I transformed to below code.
Say given number is N
then create a N x N matrix and fill it's first column with 1's
and all other cells with 0's
Start from rightmost column uptil 2nd column.
For any column X start from bottom-most row and fill values like below:
Fill 2^(N - X + 1)/2 rows with 0's.
Fill 2^(N - X + 1) rows with 1's and then 0's alternatively.
Repeat step 2 till we reach topmost row.
Print the N x N matrix by joining the values in each row.
<?php
$listN = 3;
$output = [];
for ($i = 0; $i < $listN; $i++) {
$output[$i] = [];
for ($j = 0; $j < $listN; $j++) {
$output[$i][$j] = 0;
}
}
$output[$listN - 1][0] = 1;
for ($column = 1; $column < $listN; $column++) {
$zeroFlag = false;
for ($row = $listN - 1; $row >= 0;) {
$oneZero = 1;
if (!$zeroFlag) {
for ($k = 1; $k <= pow(2, $column) / 2 && $row >= 0; $k++) {
$output[$row][$listN - $column] = 0;
$row--;
$zeroFlag = true;
}
}
for ($k = 1; $k <= pow(2, $column) && $row >= 0; $k++) {
$output[$row][$listN - $column] = $oneZero;
$row--;
}
$oneZero = 0;
for ($k = 1; $k <= pow(2, $column) && $row >= 0; $k++) {
$output[$row][$listN - $column] = $oneZero;
$row--;
}
}
}
for ($i = 0; $i < $listN; $i++) {
$output[$i][0] = 1;
}
for ($i = 0; $i < $listN; $i++) {
print(join('', $output[$i]));
print("\n");
}

PHP function - output of function is the input of another function

I have the following function where certain inputs are given and then 4 outputs are given: -
function rsiNext($dailyGainAvgPrev, $dailyLossAvgPrev,$cpDailyNext){
if($cpDailyNext > 0){
$dailyGainAvgNext = (($dailyGainAvgPrev * 13) + $cpDailyNext)/14;
}else{
$dailyGainAvgNext = (($dailyGainAvgPrev * 13) + 0)/14;
}
if($cpDailyNext < 0){
$dailyLossAvgNext = (($dailyLossAvgPrev*13) + abs($cpDailyNext))/14;
}else{
$dailyLossAvgNext = (($dailyLossAvgPrev*13) + abs(0))/14;
}
$relStrNext = $dailyGainAvgNext/$dailyLossAvgNext;
if($dailyLossAvgNext == 0){
$relStrIndNext = 100;
}else{
$relStrIndNext = 100-(100/(1+$relStrNext));
}
return array($dailyGainAvgNext, $dailyLossAvgNext, $relStrNext, $relStrIndNext);
}
I output the values using the following line of code:
//Get value for day 15
list($dailyGainAvg02, $dailyLossAvg02, $relStr02, $relStrInd02) = rsiNext($averageGains14, $averageLosses14, $priceDifferences[15]);
echo '<tr><td>'.$dailyGainAvg02.'</td><td>'.$dailyLossAvg02.'</td><td>'.$relStr02.'</td><td>'.$relStrInd02.'</td></tr>';
Now when I want the value for day 16 I use the following line of code:
//Get value for day 16
list($dailyGainAvg03, $dailyLossAvg03, $relStr03, $relStrInd03) = rsiNext($dailyGainAvg02, $dailyLossAvg02, $priceDifferences[16]);
echo '<tr><td>'.$dailyGainAvg03.'</td><td>'.$dailyLossAvg03.'</td><td>'.$relStr03.'</td><td>'.$relStrInd03.'</td></tr>';
The output of day 15 is the input of day 16, the output of day 16 is the input of day 17. The output of day 17 is the input of day 18, etc...
I need to repeat the list for 100 days. How can I go about it without repeating the list line for another 100 days?
Thank you.
Assuming you have the $priceDifferences array fully populated, something like the following should do:
$cur_dailyGainAvg = 0; // you need to initialize this value appropriately
$cur_dailyLossAvg = 0; // you need to initialize this value appropriately
for ($idx = 1; $idx <= 100; $idx++) {
list($new_dailyGainAvg, $new_dailyLossAvg, $new_relStr, $new_relStrInd) = rsiNext($cur_dailyGainAvg, $cur_dailyLossAvg, $priceDifferences[$idx])
// print
echo '<tr><td>'.$new_dailyGainAvg.'</td><td>'.$new_dailyLossAvg.'</td><td>'.$new_relStr.'</td><td>'.$new_relStrInd.'</td></tr>';
// shift the new values onto the current, and repeat the calculation
$cur_dailyGainAvg = $new_dailyGainAvg;
$cur_dailyLossAvg = $new_dailyLossAvg;
}
Basically distinguish between your "current" values, which you feed into your function, and the "new" values that come out, then "shift" the new onto the current ones and repeat.
You may have to check the boundaries of the loop.

Do an action after two rounds of a for loop

I've got a $identifier, $start_number and $end_number.
The start number is the number where the for loop should start
counting from
The end number is where the loop should stop counting
The identifier determinates how much is getting added to the start number
This for loops looks something like this:
$start_number = 102;
$end_number = 1051;
$identifier = 24;
for($i = $start_number; $i <= $end_number; $i += $identifier) {
//The first two times, add 1 to the identifier
//The second two times (we're at 4 now) add 5 to the identifier
//The third two times (were at 6 now) add 10 to the identifier
//The fourth two times (we're at 8 now) add 20 to the identifier
//etc...
}
I want it to add a dynamic number (which changes) to the $identifier each 2 times it loops, how do i do this?
Just keep track of where you are in your loop by using a counter. Then you can use the modulus operator to determine if it an even number iteration. You can add the appropriate value by using an array to store the values to add to $identifier with the count being the key to get your correct value.
$start_number = 102;
$end_number = 1051;
$identifier = 24;
$add = array(
2 => 1,
4 => 5,
6 => 10,
8 => 20
);
$count = 1;
for($i = $start_number; $i <= $end_number; $i += $identifier) {
if ($count % 2 === 0) {
$identifier += $add[$count];
}
$count++;
}
for($i = $identifier; $i <= $end_number; $i += $identifier) {
if($i%2 == 0){
//do your work
}
}

Dynamic X-axis graph that will change according to the count of rows

Let's say I have a mysql table with an id, some measurements and a DATE column.
Example: id, measurements, date_entered
This table stores some measurements of a patient so as to keep a record for him.
I want to make a graph which according to the count of rows that exist in the database will change dynamically the X-axis.
For example, if there are only 7 rows in the table I need to represent 7 days to the graph with the measurement for every day. If there are more than 14 days, I want it to change to respresent 2 weeks on X-axis and the average measurements(average for 1 week and average for the other too) on Y-axis and so on from weeks to months.
Can anyone help me on this? I cannot think of something that will do in my case..
I use JPGraph to make the line graph but i don't have a problem there. My problem is on how to handle the results.
I hope you will understand what I need! Thanks.
Something like this?
// Get the results from the database
$query = "SELECT `data_col` FROM `table` WHERE `condition_col` = 'some value'";
$result = mysql_query($query);
// Get all results into array and count them
$results = array();
for ($i = 0; $row = mysql_fetch_assoc($result); $i++) {
$results[] = $row;
}
// Re-format the data depending on number of results
$data = array();
if ($i < 14) { // Less than 14 days, show per day
foreach ($results as $row) {
$data[] = $row['data_col'];
}
} else if ($i < 56) { // Less than 8 weeks, show per-week
$thisweek = array();
for ($j = 0; isset($results[$j]); $j++) { // Loop the results
$thisweek[] = $results[$j]['data_col']; // Add result to this week total
if ($j % 7 == 0 && $j > 0) { // Every 7 days...
$data[] = array_sum($thisweek) / 7; // ...calculate the week average...
$thisweek = array(); // ...and reset the total
}
}
// If there is an incomplete week, add it to the data
$data[] = array_sum($thisweek) / count($thisweek);
} else { // 8 weeks or more, show per-month
$thismonth = array();
for ($j = 0; isset($results[$j]); $j++) { // Loop the results
$thismonth[] = $results[$j]['data_col']; // Add result to this month total
if ($j % 28 == 0 && $j > 0) { // Every 28 days...
$data[] = array_sum($thismonth) / 28; // ...calculate the month average...
$thismonth = array(); // ...and reset the total
}
}
// If there is an incomplete month, add it to the data
$data[] = array_sum($thismonth) / count($thismonth);
}
// $data now contains an array from which you should be able to draw your
// graph, where array keys are (sort of) x values and array values are y
// values.
Obviously, this solution assumes a 28-day month - it does not use the calendar, simply the number of days. You could do something horrible involving working out the stats based on some values returned by date() or similar, but this would likely drastically increase the calculation overhead and slow the process down.
Hopefully this will give you a place to start.

Fill in absent elements in an array

I have a code that generates total posts from a database per hour for the latest 10 hours. Now, the problem is that only hours with posts are displayed, but that won't work for me because i want to display the whole thing as a chart.
Example of the current array:
array("12"=>"20403",
"15"=>"17017",
"17"=>"84013");
The keys represent the hour in a 24 format. So what i need is a function that fills in the empty hours with 0 value.
Example:
$currenthour=date('H'); // i think it may be based on the latest hour.
array("11"="0",
"12"=>"20403",
"13"=>"0",
"14"=>"0",
"15"=>"17017",
"16"=>"0",
"17"=>"84013",
"18"=>"0",
"19"=>"0",
"20"=>"0");
Thanks!
foreach(range(0, 23) as $hour)
if(!isset($ary[$hour]))
$ary[$hour] = 0;
ksort($ary);
to fill in only last hours you may need something like
function last_hours($hour, $cnt) {
return $hour < $cnt - 1 ?
array_merge(range($hour, 0), range(23, 25 - $cnt + $hour)) :
range($hour, $hour - $cnt + 1);
}
and then
$now = date("G");
$new_array = array();
foreach(last_hours($now, 10) as $hour)
$new_array[$hour] = isset($ary[$hour]) ? $ary[$hour] : 0;
Use array_fill OR do it with a loop (assuming $hours is your array:
$currenthour=date('H');
for($i = $currenthour; $i < 23; $i++)
if(!isset($hours[$i]))
$hours[$i] = 0;
You can simply iterate through the array, and see if the value at the index is set. Like this:
Edit with your the last 10 hours:
$currenthour=date('H')
$beginrange = $currenthour - 10
if ($beginrange =< 0)
$beginrange = 23 + $beginrange
$endrange = $currenthour
//set up the for loop
foreach(range($beginrange, $endrange) as $i)
//check if the element is set
if(!isset($array[$i]))
// set it
$array[$i] = 0;

Categories