PHP Array ordering based on a rating formula? - php

I'm trying to order an array of results using a rating forumula I have created, it works by creating a new rating value based on time since posting.
Heres the rating formula: Ratings decrease overtime (Times are in unix timestamps format)
$new_rating = $current_rating / ($current_time - $post_time);
Array
(
[0] => Submissions Object
(
[title] => Exploits Emerge For Linux Privilege Escalation Flaw
[link] => http://test.com
[description] => test description test
[tags] => hardware,government,libya
[rating] => 10
[date] => 1327546314
)
[1] => Submissions Object
(
[title] => High School Students Send Lego Man 24 Kilometers High
[link] => http://test.com
[description] => test description test
[tags] => hardware,government,libya
[rating] => 5
[date] => 1327546305
)
)
My question is how do I sort this array using the above formula? or is their a way I can insert this formula into the mysql query statement?
Thanks a lot everyone.

You're going to want to use usort along with a custom sorting function.
function get_rating($obj)
{
$obj->rating / (time() - $obj->date);
}
function my_compare_func($a, $b)
{
$a = get_rating($a);
$b = get_rating($b);
if($a == $b) return 0;
return ($a > $b)? 1: -1;
}
usort($array_of_objs, 'my_compare_func');

You have to use usort() function.

Something along these lines of using usort should work:
usort($objects, function($a, $b) {
$rating_of_a = $a['rating'] / ($current_time - $a['date']);
$rating_of_b = $b['rating'] / ($current_time - $b['date']);
return ($rating_of_a < $rating_of_b) ? -1 : 1;
});

Related

How to change/reset PHP array type?

I have the following PHP code working to identify intersections of dates that fall on dates where we have a Full condition.
Based on this StackOverflow post :
php check multiple dates in array are within a date range
I have a working filter using a test array ($d2).
<?php
$d2 = array ('08/23/2019','08/24/2019','08/25/2019','08/26/2019','08/27/2019','08/28/2019','08/29/2019','08/30/2019','08/31/2019','09/01/2019');
$start = strtotime('08/27/2019');
$end = strtotime('08/29/2019');
foreach($d2 AS $date) {
$timestamp = strtotime($date);
if($timestamp >= $start && $timestamp <= $end) {
echo "The date $date falls on a day where we are sold out \n";
} else {
// echo "Process Reservation \n";
}
}
?>
The print_r($d2) that works looks like this:
Array
(
[0] => 08/23/2019
[1] => 08/24/2019
[2] => 08/25/2019
[3] => 08/26/2019
[4] => 08/27/2019
[5] => 08/28/2019
[6] => 08/29/2019
[7] => 08/30/2019
[8] => 08/31/2019
[9] => 09/01/2019
)
But my array which is comprised of checking existing dates, then finding which have x number of instances on a particular date. For instance, if we have 7 or more we have a full condition (sold out).
$sold_outUS = array_filter($datesUS, function($n) { return $n >= 7; });
If I print_r($sold_outUS) this array, it shows a different type of array structure:
Array
(
[08/23/2019] => 7
[08/24/2019] => 7
[08/25/2019] => 7
[08/26/2019] => 7
[08/27/2019] => 7
[08/28/2019] => 7
[08/29/2019] => 7
[08/30/2019] => 7
[08/31/2019] => 7
[09/01/2019] => 7
)
How do I change the way this array is stored so it matches the working state and what is happening that I need to learn?
Looks as though I need an independent key and value for each instance in the array. Just don’t know how to change or reset the array to be? non-multi-dimensional?
Use array_keys to get the keys of an associative array.
$sold_outUS = array_keys(array_filter($datesUS, function($n) { return $n >= 7; }));

Spliting .txt file lines in to multi-layered array key value pairs then sorting it

Since this question has a long explanation, I'll ask the question, then have the explanation below -- Can you sort a multidimensional array by their internal array key value, or is there a better way to get around sorting key value pairs that will have inevitable duplicates, than just using an array?
I am mostly unfamiliar with using PHP and want to learn how to store data.
The very simple example I made is just two HTML form inputs for a score and a name and a PHP file to handle the input to be stored in a plain .txt file, which was originally written with the pattern
42|John
32|Jane
25|John
I was able to successfully split the data, sort it, add the new inputted values then store it all back in the text file to be displayed somewhere else, using the name as the key and the score as the value.
I did all this only to realize that it would only store sort and display the last value associated with each name (i.e.)
42|John
32|Jane
25|John
would be sorted to
32|Jane
25|John
because you, obviously, can't have two of the same keys in an array, which is something I completely overlooked.
My solution, currently is to have an extra number that is unique to each name/score pair, which I formatted in the text file as
1|42|John
2|32|Jane
3|25|John
I then split them into a multidimensional array using this foreach loop
foreach($arr as $key => $value) {
$lineData = explode("|", $value);
$scores[$lineData[0]] = array($lineData[1] => $lineData[2]);
}
To get this output
Array
(
[1] => Array
(
[42] => John
)
[2] => Array
(
[32] => Jane
)
[3] => Array
(
[25] => John
)
)
which avoids overwriting any duplicate names or scores, but leaves me in a position where I can't (to my knowledge) use arsort() to sort the array in to highest to lowest.
You can use array_multisort for that, in combination with array_column. Because the key values are strings, you need to also convert them to integers, for which you can use array_map("intval", ...):
foreach($arr as $value) {
$result[] = explode("|", $value);
}
array_multisort(array_map("intval", array_column($result, 0)), $result);
After the above code has run, $result will be sorted by the key values:
[
['25', 'John'],
['32', 'Jane'],
['42', 'John']
]
To reverse the order, apply array_reverse to the result.
Alternative
You could also decide to sort the original array without conversion to a 2D array, and sort it with a custom sort callback, using usort and (again) intval:
usort($arr, function ($a, $b) {
return intval($a) - intval($b);
});
Then $arr will be sorted to:
[
'25|John',
'32|Jane',
'42|John'
]
To reverse the order, switch the position of $a and $b in the sort callback function:
return intval($b) - intval($a);
If we make a small change to your foreach iteration like this:
foreach($arr as $key => $value) {
$lineData = explode("|", $value);
$scores[] = array('score' => $lineData[1], 'name' => $lineData[2]);
}
Your array will have:
Array
(
[0] => Array
(
[score] => 42
[name] => John
)
[1] => Array
(
[score] => 32
[name] => Jane
)
[2] => Array
(
[score] => 25
[name] => John
)
)
You can use the uasort function, which takes the array to sort, and an user-defined function to do the sorting. The code would look like this:
function compare($a, $b)
{
if ($b['score'] == $a['score']) {
if ($a['name'] == $b['name']) {
return 0;
} elseif ($a['name'] < $b['name']) {
return -1;
} else {
return 1;
}
} else {
return ($b['score'] - $a['score']);
}
}
print_r($scores);
uasort($scores, 'compare');
print_r($scores);
Which gives the following result:
Array
(
[1] => Array
(
[score] => 32
[name] => Jane
)
[2] => Array
(
[score] => 25
[name] => John
)
[0] => Array
(
[score] => 42
[name] => John
)
)
When you use a user-defined function for the sorting you need to return one of 3 values (0 of the values as equal, -1 if $a < $b, and 1 if $b > $a. In this case we're sorting first by score (descending), then by name (ascending). Since you need to order from highest to lowest score, the comparison is $b against $a, for ascending order is $a against $b. I didn't consider the extra number necessary. If you need it then change this line:
$scores[] = array('score' => $lineData[1], 'name' => $lineData[2]);
To this:
$scores[$lineData[0]] = array('score' => $lineData[1], 'name' => $lineData[2]);

Get highest value in multi multidimensional array [duplicate]

This question already has answers here:
Find highest value in multidimensional array [duplicate]
(9 answers)
Closed 5 years ago.
i need to get the the max or highest value in a multi dimensional array.
here is my array $array:
[pay] => Array
(
[0] => Array
(
[title] => Array
(
[name] => 'hi'
)
[payment] => Array
(
[amount] => 35
[currency] => USD
)
)
[1] => Array
(
[title] => Array
(
[name] => 'lol'
)
[payment] => Array
(
[amount] => 50
[currency] => USD
)
)
[2] => Array
(
[title] => Array
(
[name] => 'ok'
)
[payment] => Array
(
[amount] => 30
[currency] => USD
)
)
)
i need to get the max value for amount which is 50. how can i do that?
here is what i tried but it did not work:
$max = -9999999; //will hold max val
$found_item = null; //will hold item with max val;
foreach($array as $k=>$v)
{
if($v['Total']>$max)
{
$max = $v['Total'];
$found_item = $v;
}
}
Simple as this one-liner. Get the payment column data, then pull the amount data from that generated array, then get the max value. Done and done. (Sorry it took me so long -- I had to convert your posted array to a usable php array.)
Input:
$array=["pay" => [
["title"=>["name"=>'hi'],"payment"=>["amount"=>35,"currency"=>"USD"]],
["title"=>["name"=>'lol'],"payment"=>["amount"=>50,"currency"=>"USD"]],
["title"=>["name"=>'ok'],"payment"=>["amount"=>30,"currency"=>"USD"]]
]
];
Method #1 (Demo):
echo max(array_column(array_column($array["pay"],"payment"),"amount"));
Method #2 (Demo):
$max=0;
foreach($array["pay"] as $subarray){
if($max<$subarray["payment"]["amount"]){
$max=$subarray["payment"]["amount"];
}
}
echo $max;
Method #3 (Demo):
$payments=array_column($array["pay"],"payment"); // declare payments array
rsort($payments); // sort by amount DESC
echo $payments[0]["amount"]; // access the first amount value
Output:
50
The benefits to method #1 are: code brevity, no condition statements, no global variable declarations/overwriting, just straight to the max value. What's not to love!
If method #1 is too scary, you can go with my method #2 (which was first posted by aendeerei). I don't prefer it because it requires the extra steps of initializing the $max variable, performing a conditional check on each iteration, and overwriting the $max variable when appropriate. Actual performance on the foreach loop is going to depend on the size of your array, but the difference between the two methods is going to be unnoticable to humans.
Method 3 might be my new favorite because there are no conditionals and just two functions before it is accessed purely by keys. However, it does require the declaration of a partial copy of the input array which must be sorted. Anyhow, take your pick -- it's all the same outcome.
Use Usort and get the 1st index
$arr= array
(
array
(
'payment' => array
(
'amount' => 35,
'currency' => 'USD'
)
),
array
(
'payment' => array
(
'amount' => 50,
'currency' => 'USD'
)
),
array
(
'payment' => array
(
'amount' => 80,
'currency' => 'USD'
)
)
);
function sortAmount($x, $y) {
return $y['payment']['amount'] - $x['payment']['amount'];
}
usort($arr, 'sortAmount');
echo "<pre>";
$highest=$arr[0];
print_r($highest)
//for value only
$highest=$arr[0]['payment']['amount'];
Working fiddle
http://phpfiddle.org/main/code/p5hw-ivei
$max = 0;
foreach ($array['pay'] as $key => $item) {
$amount = $item['payment']['amount'];
if ($amount > $max) {
$max = $amount;
}
}
echo $max;
Shorthand:
$result = array_reduce($array['pay'], function($a, $b){
return $a ? ($a['payment']['amount'] > $b['payment']['amount'] ? $a : $b) : $b;
});
var_dump($result['payment']['amount']);
Try this hope this will be helpful. Here we are just using simple foreach to get it done.
Solution 1:
try this code snippet here
$max=0;
foreach($yourArray["pay"] as $value)
{
if($max<$value["payment"]["amount"])
{
$max=$value["payment"]["amount"];
}
}
echo $max;
Solution 2:
Just for testing purpose i have converted you array to json. Here we are using array_column two times to get the columns
Try this code snippet here
$internals=array_column($yourArray["pay"],"payment");//retrieving payments
$amounts=array_column($internals, "amount");//retrieving amounts
arsort($amounts);
print_r(array_values($amounts)[0]);
Consider this example with an array named pay. You can adapt this method for your own array. This code will work for an array of n elements. Here I consider 3 as the number of elements in the array named $pay. You can replace the max elements in the array in the place of 3 for controlling the loop control variable 'i'.
$big=$pay[0];
for($i=1; $i<3; $i++){
if($pay[i]>$big)
$big=$pay[i];
}
echo $big;
I hope this is what you are looking for. Ask for any clarification.

How to sort array by something in php? [duplicate]

This question already has answers here:
Sort array of objects by one property
(23 answers)
Closed 9 years ago.
I have a data like this
array([0] => stdClass Object ( [id] => 1 [title] => AAAA [sentence] => abcdefgh [rank] => 3 ) [1] => stdClass Object ( [id] => 2 [title] => BBBB [sentence] => ijklmn [rank] => 1 ) [3] => stdClass Object ( [id] => 3 [title] => CCC [sentence] => opqrstu [rank] => 2 ));
Show the data:
foreach($data as $d)
{
$title = $d->title;
$sentence = $d->sentence;
$rank = $d->rank;
echo $title. " | " .$sentence. " | " .$rank. "<br>";
}
How to sort it by 'rank'? Thanks for your help.
You can use PHP's usort with a function that uses objects' attribute rank as criteria:
function rank_compare($a, $b) {
return $a->rank - $b->rank;
}
usort($data, 'rank_compare');
More info: http://www.php.net/manual/en/function.usort.php
use php's usort function
usort($array, function($a, $b){
if ($a->rank == $b->rank) return 0;
return ($a->rank > $b->rank)?1:-1;
});
usort takes the array and a comparison function, the comparison function should return 0 if the two parameters are equal in terms of the sort, 1 if the first argument is greater then the second argument and -1 if the first argument is less then the second.
This is where your classes on bubble sorting come in handy. You write yourself a handy little sorting algorithm that takes in an array as an argument, returns an array of sorted stuff... and it's just a couple of for loops. Outer loop is from 0 to the length of the array. Inner loop is from 0 to the length of the array minus the outer loop. And for the inner loop, compare current value to next value - if current value is 'bigger', bubble it up. After the first time through the outer loop, the biggest value is at the top. After the second time through, the second biggest is second from the top. Etc.

PHP sort multi dimensional array

How can I sort this first by Member id and then by Payment date?
Array
(
[240] => Array
(
[Member] => Array
(
[id] => 112
)
[Payment] => Array
(
[date] => 0712
)
)
I tried with multisort, but I never found a way what was working and all examples I found didn't had my additional level.
Is the date value a string or an integer?
Anyway, supposing that date is an int, you could try this:
function my_sort($val1, $val2) {
$compare_id = $val1['Member']['id'] - $val2['Member']['id'];
if($compare_id == 0) {
return $val1['Payment']['date'] - $val2['Payment']['date'];
}
else return $compare_id;
}
and then call:
usort($array, 'my_sort');
If the data is received from database you can use ... ORDER BY member,date

Categories