PHP - Ranking in different dates starting from multidimensional array - php

I'm storing in a multi-dimensional array the progressive score of n players in different days.
So I've something like
Array
(
[0] => Array
(
[day] => 2014-10-01
[player] => John
[score] => 1500
)
[1] => Array
(
[day] => 2014-10-02
[player] => John
[score] => 1510
)
[2] => Array
(
[day] => 2014-10-01
[player] => Mary
[score] => 1400
)
[3] => Array
(
[day] => 2014-10-02
[player] => Mary
[score] => 1600
)
)
What I need a day-by-day rank for a given player, comparing his score with all other players's one, for each day.
So the input will be player's id (in this case "John") and the output should be a JSON object like
[{"day"="2014-10-01", "rank": 1}, {"day"="2014-10-02", "rank": 2}]
What's the best way to approach this problem?
To give you an idea of the dimension of my data, consider that I've the scores of 100 players in 100 different days (so I've a table of approximately 10.000 records).
EDIT (27/11/14): the multi-dimensional array is the result of a pre-processing on data stored in
a MySQL database.
This database contains information about each game played in this form:
|Date |WinnerId|LoserId|PtsEarned|PtsLost|
|2014-10-01|John |Mary |10 |-10 |
|2014-10-02|Mary |John |20 |-20 |
So I don't know If I can easily use the method suggested in the "duplicate" answer.
With my first approach, it takes about 7-8 seconds to output the result I need... so I think It's not the most efficient way to face the problem...
EDIT (28/11/14): I tried ranking data directly in MySql, and it takes about 2 seconds to give me back the ranking position of one player in a specific day; repeating the same query 100 times is a way too long process...
With a different approach I manage to create a php array with "pre-processed" data in the same time (2 seconds), but I miss the last step, i.e. how to do a rank using php functions on a multi-dimensional array (my first question). Any idea?

Related

PHP Array Loop Help - WordPress ACF

I am creating a leaderboard in WordPress. The user submits their mileage along with the date and method in an ACF repeater field. I am pulling the data and need to output the following $leaderboard array:
Array ( [user1] => Array ( [walking] => 2 [overall_mileage] => 11 [swimming] => 9 ) [user2] => Array ( [running] => 54.25 [overall_mileage] => 54.25 ) )
I am calculating the mileage and inserting it into the array.
What's the best way to loop through this into a table so that it displays in a leaderboard with a breakdown as follows?
USERNAME | SWIMMING | WALKING | RUNNING | OVERALL MILES
Thanks in advance

Serialized array of relations to Laravel relations

I'm facing one problem and I can't find the perfect and best optimized solution.
So I'm kindly asking for your opinion.
Here's what bothering me.
I've got a serialized array from DB that looks like this:
a:6:{s:13:"property_type";s:1:"1";s:16:"property_feature";a:2:{i:0;s:1:"3";i:1;s:1:"4";}s:19:"property_offer_type";s:1:"5";s:19:"property_built_type";a:1:{i:0;s:2:"10";}s:24:"properties_office_phones";s:2:"13";s:15:"property_labels";a:1:{i:0;s:1:"8";}}
Here is the non-serialized version for more clarity:
Array(
[property_type] => 1
[property_feature] => Array
(
[0] => 3
[1] => 4
)
[property_offer_type] => 5
[property_built_type] => Array
(
[0] => 10
)
[properties_office_phones] => 13
[property_labels] => Array
(
[0] => 8
))
All of this keys values are stored in one single table.
This is how the table looks like:
ID | Name | Slug | .. etc
1 | A name here | a-name-here | .. other
What do you think will be the best and most optimized way to get the information related to those IDs using Laravel 8 relations, so it can be retrieved as relations just like "with()" is doing.
Thanks in advance!

php mysql check if vendor has 3 low consecutive ratings

on my ratings table for my software i have 4 fields.
id autoincrement
rvid vendor id
ratedate date of rating
rating the actual numeric rating
I have done alot with it over the last few months but this time im stumped and i cant get a clear picture in my head of the best way to do this. What i am trying to do is find out if the vendor has had 3 low 'consecutive' ratings. If their last three ratings have been < 3 then i want to flag them.
I have been playing with this for a few hours now so i thought i would ask (not for the answer) but for some path direction just to push me forward, im stuck in thought going in circles here.
I have tried GROUP BY and several ORDER BY but those attempts did not go well and so i am wondering if this is not a mysql answer but a php answer. In other words maybe i just need to take what i have so far and just move to the php side of things via usort and the like and do it that way.
Here is what i have so far i did select id as well at first thinking that was the best way to get the last consective but then i had a small breakthrough that if they have had 3 in a row the id does not matter, so i took it out of the query.
$sql = "SELECT `rvid`, `rating` FROM `vendor_ratings_archive` WHERE `rating` <= '3' ORDER BY `rvid` DESC";
which give me this
Array
(
[0] => Array
(
[rvid] => 7
[rating] => 2
)
[1] => Array
(
[rvid] => 5
[rating] => 1
)
[2] => Array
(
[rvid] => 5
[rating] => 0
)
[3] => Array
(
[rvid] => 5
[rating] => 3
)
)
this is just just samples i tossed in the fields, and there are only 4 rows here where as in live it will be tons of rows. But basically this tells me that these are the vendors that have low ratings in the table. And that is where i get stumpted. I can only do one sort in the query so that is why i am thinking that i need to take this and move to the php side to finish it off.
I think i need to sort the elements by rvid with php first i think, and then see if three elements in a row are the same vender (rvid).
Hope that makes sense. My brain hurts lol...
update - here is all of the table data using *
Array
(
[0] => Array
(
[id] => 7
[rvid] => 7
[ratedate] => 2016-05-01
[rating] => 2
)
[1] => Array
(
[id] => 8
[rvid] => 5
[ratedate] => 2016-05-01
[rating] => 1
)
[2] => Array
(
[id] => 6
[rvid] => 5
[ratedate] => 2016-05-01
[rating] => 0
)
[3] => Array
(
[id] => 5
[rvid] => 5
[ratedate] => 2016-05-01
[rating] => 3
)
)
Here's one way you can begin approaching this - completely in SQL:
Get the last rating for the vendor. ORDER BY date DESC, limit 1.
Get the second to last rating for the vendor. ORDER BY date DESC, limit 1, OFFSET 1.
Then write a query that does a LEFT join of the first two tables. You will have a dataset that has three columns:
vendor id
last rating
second to last rating
Then you can write an expression that says "if column1 is <3 and column2 < 3, then this new column is true"
You should be able to extend this to three columns relatively easily.
Here is what a came up with to solve this riddle. I think explaining it on here helped as well as Alex also helped as he keyed my brain on using the date. I first started looking at using if statment inside of the query and actually that got my brain out of the box and then it hit me what to do.
It is not perfect and certainly could use some trimming to reduce the code, but i understand it and it seems to work, so that is par for me on this course.
the query...
$sql = "SELECT `rvid`, `ratedate`,`rating` FROM `vendor_ratings_archive` WHERE `rating` <= '3' ORDER BY `ratedate`, `rvid` DESC";
which gives me this
Array
(
[0] => Array
(
[rvid] => 7
[ratedate] => 2016-05-01
[rating] => 2
)
[1] => Array
(
[rvid] => 5
[ratedate] => 2016-05-01
[rating] => 1
)
[2] => Array
(
[rvid] => 5
[ratedate] => 2016-05-01
[rating] => 0
)
[3] => Array
(
[rvid] => 5
[ratedate] => 2016-05-01
[rating] => 3
)
)
notice how vendor (rvid) 5 is grouped together which is an added plus.
next a simple foreach to load a new array
foreach($results as $yield)
{
$rvidarray[] = $yield['rvid'];
}//close foreach
which gives me this
Array
(
[0] => 7
[1] => 5
[2] => 5
[3] => 5
)
then we count the array values to group dups
$rvidcounter = array_count_values($rvidarray);
which results in this
Array(
[7] => 1
[5] => 3
)
so now vender 7 as 1 low score and vendor 5 has 3 low scores and since they were already sorted by date i know that its consecutive. Well it sounds good anyway lol ")
then we create our final array with another foreach
foreach($rvidcounter as $key => $value)
{
//anything 3 or over is your watchlist
if($value > 2)
{
$watchlist[] = $key; //rvid number stored
}
}//close foreach
which gives me this
Array
(
[0] => 5
)
this was all done in a service function. So the final deal is everyone in this array has over 3 consecutive low ratings and then i just use a returned array back in my normal php process file and grab the name of each vender by id and pass that to the html and print out the list.
done...
please feel free to improve on this if you like. I may or may not use it because the above code makes sense to me. Something more complicated may not make sense to me 6 mos from now lol But it would be interesting to see what someone comes up with to shorten the process a bit.
Thanks so much and Happy Coding !!!!!
Dave :)
You could do it in SQL like that:
SET #rvid = -1;
SELECT DISTINCT rvid FROM
(
SELECT
rvid,
#neg := rating<3, /* 0 or 1 for addition in next line */
#count := IF(#rvid <> rvid , #neg, #count+#neg) AS `count`, /* set or add */
#rvid := rvid /* remember last row */
FROM
testdb.venrate
ORDER BY
rvid, datetime desc
) subq
WHERE count>=3
;
You set a variable to a non existing id. In each chronologically sorted row you check if rating is too low, that results in 1 (too low) or 0 (ok). If rvid is not equal to the last rvid, it means a new vender section is beginning. On begin of section set the value 0 or 1, else add this value. Finally store the current row's rvid for comparison in next row process.
The code above is looking for 3 consecutive low ratings (low means a value less than 3) over all the time.
A small modification checks if all the latest 3 ratings has been equal to or less than 3:
SET #rvid = -1;
SELECT DISTINCT
rvid
FROM
(
SELECT
rvid,
#high_found := rating>3 OR (#rvid = rvid AND #high_found) unflag,
#count := IF(#rvid <> rvid , 1, #count+1) AS `count`,
#rvid := rvid /* remember last row */
FROM
testdb.venrate
ORDER BY
rvid, datetime desc
) subq
WHERE count=3 AND NOT unflag
;

PHP & MySQL, laying out in CSV format with special parameters

I have a database that has budgets in them (for this, I have modified the budgets to be fake).
Long story short, I am attempting to run the following SQL query on the database, and then display a report based on it.
Here is the query: SELECT MONTHNAME(date) AS month, product, SUM(amount) AS spend FROM client_budgets WHERE advertiser_id = '$advertiser_id' GROUP BY MONTHNAME(date), product ORDER BY MONTH(date) ASC
I then clean the data a little, here is the code for that:
foreach($data AS $key => $val) {
$clean_data[] = $val;
}
From this, I get the following (this is a PHP array of the data. I have cut it off since it has about 100K rows in the database currently).
Array
(
[0] => Array
(
[month] => January
[product] => Internet
[spend] => 12000.00
)
[1] => Array
(
[month] => January
[product] => Radio
[spend] => 12250.00
)
[2] => Array
(
[month] => February
[product] => Billboards
[spend] => 6000.00
)
[3] => Array
(
[month] => February
[product] => Internet
[spend] => 16000.00
)
)
My goal is to end up being able to display in a CSV (I already have the headers set for the CSV), the following:
Month, Internet, Radio, Billboards, Television
January, 12000, 12250, 6000, 0
February, 16000, 7000, 6000, 2000
....
I am stuck right now trying to sort the data correctly, and if there is no data for Television for instance one month, to display a 0. Any help would be appreciated! I have been attempting this for almost 3 days now.

Insert Array values, multiple rows

I'm trying to record some information on a database. My post looks like this:
Array
(
[Action] => 1000
[Date_Stat] => 07/02/2013
[Date_Final] => 07/02/2013
[Product_Id] => Array
(
[0] => 2
[1] => 6
[2] => 1
)
[Conversion] => Array
(
[0] => 1,20
[1] => 1,00
[2] => 2,03
)
[ValueMin] => Array
(
[0] => 2,00
[1] => 1,58
[2] => 2,70
)
[ValueMax] => Array
(
[0] => 2,50
[1] => 1,98
[2] => 2,90
)
[ValueMedio] => Array
(
[0] => 2,20
[1] => 1,68
[2] => 2,80
)
)
HOW can I insert all this on database the right way?
I'm not sure about the best way to design the tables and store the information. I'm using this to make a PRICE TABLE with starting date, final date and list all products with prices.
Also I'm thinking what is the best method. There are 2 possibilities I think about
Date_Start | Date_End |Product_Id | ValueMin | ValueMax | ValueMedio | Conversion
02-02-2013 02-03-2013 1 1.00 2.00 3.00 4.00
02-02-2013 02-03-2013 2 1.00 2.00 3.00 4.20
02-02-2013 02-03-2013 3 1.00 2.00 2.00 4.40
OR (using implode and putting all values on the same row)
Date_Start | Date_End |Product_Id | ValueMin | ValueMax | ValueMedio | Conversion
02-02-2013 02-03-2013 1,2,3 1,1,1 2, 2,2 3,3,2 4, 4.3, 4.4
Thanks a lot!
Choose the option mentioned first. Selecting Rows will become much easier if you do it that way.
To insert the records, use a simple prepared Statement (PHP Manual) and use a for-Loop.
I'd suggest a little tweak over the first option. If you create a separate table (Something along the lines of "Prices") like this:
id|DateStart|DateEnd|
1|02-02-2013|02-02-2013|
And then, in the table you suggested, you'd replace the date range for the PriceId (Foreign Key to this table). That way it'll be easier for you to maintain the consistency over changes on date ranges.

Categories