Count array counts 1 too many - php

Does anyone know how to get arround the annoying problem that when counting how many values there is inside an array if the value is 0 it says 1 becuase it counts the name or something. So like this:
0 : 1
1 : 1
2 : 2
3 : 3
4 : 4
5 : 5
6 : 6
7 : 7
8 : 8

To fully answer the question, I'd need the code for this.
My sneaking suspicion is that whatever you are count()ing isn't an empty array the first time, but something else. An initialized, non-null, non-array and non-Countable-object variable has a count() of 1.
See count's documentation for more info.

Related

Get the most popular input data input in MySQL with PHP [duplicate]

This question already has an answer here:
What to do with mysqli problems? Errors like mysqli_fetch_array(): Argument #1 must be of type mysqli_result and such
(1 answer)
Closed 1 year ago.
I'm trying to make a website to keep the best time records on my website. Currently I'm struggling to get the most popular levels.
I'm using MySQL in combination with phpMyAdmin (for the manual input) and PHP to manage my tables. Currently I'm using a table recordData to keep track of certain records. The table consists of a uniqueID(int) (A.I.), time(int), timeUsername(varchar) (the player with the time), timeLevelID(int) (the level played) and some other irrelevant data.
What I want is an output of the int data in timeLevelID that got used the most. Please see the following data to simplify this concept:
uniqueID
timeLevelID
1
6
2
2
3
31
4
31
5
6
6
6
Where the desired output is a sorted count table, descending by count data:
timeLevelID
count
6
3
31
2
2
1
What I've tried so far:
First attempt, I tried messing around with the SQL query, but somehow I never got it to work.
require_once "dbConnect.php";
$allRecordsDataSQL="SELECT timeLevelID COUNT(timeLevelID) AS timeLevelIDFrequency FROM recordData GROUP BY timeLevelID ORDER BY timeLevelIDFrequency DESC";
$allRecordsData = $conn->query($allRecordsDataSQL);
print_r($allRecordsData);
while($row=$allRecordsData->fetch_array(MYSQL_ASSOC)){
echo $row["timeLevelID"];
}
This creates the following error, and also doesn't return anything on the print_r - I assume $allRecordsData is false?
Fatal error: Uncaught Error: Call to a member function fetch_array() on boolean
In my second attempt I tried catching all the data in a new array. The new array would count the amount of levels each level has, After which I sort the array and output it's data.
require_once "dbConnect.php";
$allRecordsDataSQL="SELECT timeLevelID FROM recordData";
$allRecordsData = $conn->query($allRecordsDataSQL);
$arrayCounter = array_fill(1, $allRecordsData->num_rows, 0);
while($row = $allRecordsData->fetch_array(MYSQLI_ASSOC)){
$arrayCounter[$row["timeLevelID"]]++;
}
rsort($arrayCounter);
foreach($arrayCounter as $key => $val){
echo "<br>";
echo "$key = $val\n";
}
The second attempt does work PHP wise, but the output is the following, and I've got no clue what to do with this:
0 = 4
1 = 3
2 = 3
3 = 3 ..etc..
I assume my first attempt has a silly mistake but I just can't seem to spot it (I'm new to MySQL & PHP, sorry). Nevertheless, I do think the first attempt is the most efficient so I'd like to solve my issue this way.
You have not included the source code of your dbConnect.php file. It appears to be suppressing the errors which is why you did not get an exception thrown for the error in your SQL query. There's a comma missing after timeLevelID in the SELECT list -
require_once "dbConnect.php";
$allRecordsDataSQL="SELECT timeLevelID, COUNT(timeLevelID) AS timeLevelIDFrequency FROM recordData GROUP BY timeLevelID ORDER BY timeLevelIDFrequency DESC";
$allRecordsData = $conn->query($allRecordsDataSQL);
Using var_dump instead of just print_r will often tell you more (boolean false perhaps) -
var_dump($allRecordsData);
while($row=$allRecordsData->fetch_array(MYSQL_ASSOC)){
echo $row["timeLevelID"];
}

Reverse ranking order numbers , without an array

Let's say we have a ranking system with integers 1 till a maximum of 100.000 .
I want a function that reverses the rank of an integer.
So that value 100.000 becomes rank 1 and value 1 becomes rank 100.000 .
function reverseRank($currentRank,$maxRank){
// create array with numbers 1 till $maxRank.
// reverse order of values and return key of $currentRank...
// but this seems a bit a waste of resources.
return $reversedRank;
}
What would be the best way to do this performance wise in php ?
Lets assume for simplicity that you have a range of ranks between 1 and 10.
We need to find a mapping function that will swap
1 -> 10
2 -> 9
3 -> 8
4 -> 7
5 -> 6
6 -> 5
7 -> 4
8 -> 3
9 -> 2
10 -> 1
Now it might be easier to think about the solution.
What function will work for it? This function will have a couple of things known in the runtime.
Lower and upper bands of the range, so 1 and 10 respectively.
We can sketch this in slightly more formal way:
f(1) -> 10
f(2) -> 9
f(3) -> 8
(...)
f(x) -> y; // 1 and 10 are know to be the limits
what if we try to apply
Lets try playing with it. f(1) to be 10 could be:
def f(x):
return x*UPPER_LIMIT
Definitely it will break as soon as we try it with 2.
F(2) -> 9, looking at this I am able to observe that I can write it as:
Lets return a number that is as much smaller from UPPER limit as the x is more than LOWER limit.
def f(x):
return UPPER_LIMIT - (x-LOWER_LIMIT)
And, by running it for more values it looks like it works.
I hope I understood your question and that helps.

How do I use modulus with a reverse php loop?

http://viper-7.com/6soAKr
I'm trying to display a list of items in groups of 4. If I go from 1-10 in the for loop, it works great and I get the following output:
1 2 3 4
5 6 7 8
9 10
I'm using this code: http://viper-7.com/6soAKr
I actually need to display them in reverse order from 10-1 in the same format
When I try the code in reverse order:
($sucid = 10; $sucid > 0; $sucid = $sucid - 1)
I get:
10 9 8
7 6 5 4
3 2 1
And the HTML layout is out of place compares to the output of the top
What I need is:
10 9 8 7
6 5 4 3
2 1
I know it's the modulus part that is wrong, but I am having trouble understanding how to change it when I go backwards
http://viper-7.com/6soAKr
You could keep the first for-loop (i.e. the one looping from 1 to 10) and instead of $sucid print 11-$scuid.

mysql between question

For the mysql "between" operator, is it necessary for the before and after value to be numerically in order?
like:
BETWEEN -10 AND 10
BETWEEN 10 AND -10
Will both of these work or just the first one?
Also, can I do:
WHERE thing<10 AND thing>-10
Will that work or do I have to use between?
Lastly, can I do:
WHERE -10<thing<10
?
BETWEEN -10 AND 10
This will match any value from -10 to 10, bounds included.
BETWEEN 10 AND -10
This will never match anything.
WHERE thing<10 AND thing>-10
This will match any value from -10 to 10, bounds excluded.
Also, if thing is a non-deterministic expression, it is evaluated once in case of BETWEEN and twice in case of double inequality:
SELECT COUNT(*)
FROM million_records
WHERE RAND() BETWEEN 0.6 AND 0.8;
will return a value around 200,000;
SELECT COUNT(*)
FROM million_records
WHERE RAND() >= 0.6 AND RAND() <= 0.8;
will return a value around 320,000
The min value must come before the max value. Also note that the end points are included, so BETWEEN is equivalent to:
WHERE thing>=-10 AND thing<=10
Please keep it to one question per post. Anyway:
http://dev.mysql.com/doc/refman/5.0/en/comparison-operators.html#operator_between
BETWEEN min AND max, in that order.
from the link:
This is equivalent to the expression (min <= expr AND expr <= max) if
all the arguments are of the same type
The second alternative will also work, of course.
First question:
Will both of these work or just the first one?
yes,both of these work
Second question:
Will that work or do I have to use between?
it also valid but as you can see just empty result
Yes your between must be in order to return the excepted result.
Let's say you have a table with a row called mynumber that contains 10 rows :
MyNumber
--------
1
2
3
4
5
6
7
8
9
10
So
select * from thistable table where table.myNumber BETWEEN 1 and 5
will return
1
2
3
4
5
but
select * from thistable table where table.myNumber BETWEEN 5 and 1
return nothing.
Your 2nd question : yes it is the same thing. but beware in you example you will have to put <= and >= to be the same as between. if not, in our example, you would get
2
3
4
Hope it help
I've already seen such things work with integers :
WHERE -10
But it's better to avoid it. One reason is that it doesn't seem to work well with other types. And MySQL doesn't issue any warning.
I've tried it with datetime columns, and the result was wrong.
My request looked like this one:
SELECT *
FROM FACT__MODULATION_CONSTRAINTS constraints
WHERE constraints.START_VALIDITY<= now() < constraints.END_VALIDITY
The result was not as expected. I got twice as many results as the same request with two inequalities (which returned correct results). Only the 1st part of the expression evaluated correctly.

How do I find all peaks and troughs of tidal data?

I'm working with some ocean tide data that's structured like this:
$data = array('date' => array('time' => array('predicted','observed')));
Here's a sample of real data that I'm using: http://pastebin.com/raw.php?i=bRc2rmpG
And this is my attempt at finding the high/low values: http://pastebin.com/8PS1frc0
Current issues with my code:
When the readings fluctuate (as seen in the 11/14/2010=>11:30:00 to 11/14/2010=>11:54:00 span in the sample data), it creates a "wobble" in the direction logic. This creates an erroneous Peak and Trough. How can I avoid/correct this?
Note: My method is very "ad-hoc".. I assumed I wouldn't need any awesome math stuff since I'm not trying to find any averages, approximations, or future estimations. I'd really appreciate a code example of a better method, even if it means throwing away the code I've written so far.
I've had to perform similar tasks on a noisy physiological data. In my opinion, you have a signal conditioning problem. Here is a process that worked for me.
Convert your time values to seconds, i.e. (HH*3600)+(MM*60)+(SS), to generate a numeric "X" value.
Smooth the resulting X and Y arrays with a sliding window, say 10 points in width. You might also consider filtering data with redundant and/or bogus timestamps in this step.
Perform an indication phase detection by comparing the smoothed Y[1] and Y[0]. Similar to the post above, if (Y[1] > Y[0]), you may assume the data are climbing to a peak. If (Y[1] < Y[0]), you may assume the data are descending to a trough.
Once you know the initial phase, peak and trough detection may be performed as described above: if Y[i] > Y[i+1] and Y[i] < Y[i-1], you have encountered a peak.
You can estimate the peak/trough time by projecting the smoothed X value back to the original X data by considering the sliding window size (in order to compensate for "signal lag induced" by the sliding window). The resulting time value (in seconds) can then be converted back to an HH:MM:SS format for reporting.
You're looking for local minima and maxima, I presume? That's really easy to do:
<?php
$data = array(1, 9, 4, 5, 6, 9, 9, 1);
function minima($data, $radius = 2)
{
$minima = array();
for ($i = 0; $i < count($data); $i += $radius)
{
$minima[] = min(array_slice($data, $i, $radius));
}
return $minima;
}
function maxima($data, $radius = 2)
{
$maxima = array();
for ($i = 0; $i < count($data); $i += $radius)
{
$maxima[] = max(array_slice($data, $i, $radius));
}
return $maxima;
}
print_r(minima($data));
print_r(maxima($data));
?>
You just have to specify a radius of search, and it will give you back an array of local minima and maxima of the data. It works in a simple way: it cuts the array into segments of length $radius and finds the minimum of that segment. This process is repeated for the whole set of data.
Be careful with the radius: usually, you want to select the radius to be the average distance from peak to trough of the data, but you will have to find that manually. It is defaulted to 2, and that will only search for minima/maxima within a radius of 2, which will probably give false positives with your set of data. Select the radius wisely.
You'll have to hack it into your script, but that shouldn't be too hard at all.
I haven't read it in detail, but your approach seems very ad-hoc. A more correct way would probably be to fit it to a function
f(A,B,w,p;t)=Asin(wt+p)+B
using a method such as non-linear least squares (which unfortunately has to be solved using an iterative method). Looking at your sample data, it seems like it would be a good fit. When you have calculated w and p, it's easy to locate the peaks and valleys by just taking the time derivative of the function and solving for zero:
t = (pi(1+2n)-2p)/w
But I suppose, that if your code really does what you want, there's no use to complicate things. Stop second-guessing yourself. :)
A problem is I think that the observations are observations and can contain small errors. That at least needs to be accounted for. For example:
Only change direction if at least the next 2 entries are also in the same direction.
Don't let decisions be made by data on a too small difference. Throw away insignificant numbers. It will be a lot better probably when you say $error = 0.10; and change your conditions to if $previous - $error > $current etcetera.
How accurate does the peak/valley detection have to be? If you just need to find the exact record where a peak or valley occurs, isn't it enough to check for inflection points?
e.g. considering a record at position 'i', if record[i-1] and record[i+1] are both "higher" than record[i], you've got a valley. and if record[i-1] and record[i+1] are both lower than record[i], you've got a peak. As long as your sampling rate is faster than the tide changes (look up Nyquist frequency), that process should get you your data's peaks/troughs.
If you need to generate a graph from this and try to extrapolate more accurate time points for the peaks/troughs, then you're in for more work.
One way may be to define an absolute or relative deviation past which you classify further peaks/troughs as new ones rather than fluctuations around an existing peak/trough.
Currently, $direction determines whether you are finding a peak or trough, so instead of transiting to the other state (finding the trough or peak) once the derivative changes in sign, you can consider changing the state only when the deviation from the current peak/trough is "large" enough.
Given that you should never see two max or 2 min in less than about 12 hours, a simple solution would be to use a sliding windows of 3-5 hr or so and find the max and min. If it ends up being the in the first or last 30 min, ignore it.
As an example, given the following data:
1 2 3 4 5 6 5 6 7 8 7 6 5 4 3 2 1 2
and a window of size 8, with the first and last 2 ignored and only looking a peeks you would see:
1 2 | 3 4 5 6 | 5 6, max = 6, ignore = Y
2 3 | 4 5 6 5 | 6 7, max = 7, ignore = Y
3 4 | 5 6 5 6 | 7 8, max = 8, ignore = Y
4 5 | 6 5 6 7 | 8 7, max = 8, ignore = Y
5 6 | 5 6 7 8 | 7 6, max = 8, ignore = N
6 5 | 6 7 8 7 | 6 5, max = 8, ignore = N
5 6 | 7 8 7 6 | 5 4, max = 8, ignore = N
6 7 | 8 7 6 5 | 4 3, max = 8, ignore = N
7 8 | 7 6 5 4 | 3 2, max = 8, ignore = Y
8 7 | 6 5 4 3 | 2 1, max = 8, ignore = Y
7 6 | 5 4 3 2 | 1 2, max = 7, ignore = Y

Categories