I have two arrays, percentiles and percentile_bounds and another int value total_score. Given the total score, I want to return the percentile in which this value is. Ie. I want to return a value from percentiles which corresponds to placing the total_score within the percentile_bounds. In python, I would do:
import numpy as np
percentiles = np.array([ 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95])
percentile_bounds = np.array([ 84, 104, 109, 115, 120, 123, 125, 127, 129, 132, 135, 136, 137, 139, 141, 145, 148, 151, 155, 159])
# example 1
total_score = 130
print(percentiles[np.where(percentile_bounds==(percentile_bounds[percentile_bounds<total_score][-1]))])
# 40
# example 2
total_score = 153
print(percentiles[np.where(percentile_bounds==(percentile_bounds[percentile_bounds<total_score][-1]))])
# 85
# example 3
total_score = 100
print(percentiles[np.where(percentile_bounds==(percentile_bounds[percentile_bounds<total_score][-1]))])
# 0
and I found a way in PHP (function sources: 1, 2) but it is very clumsy and long:
<?php
// Example 4
$total_score = 120;
$percentile_bounds = [84, 104, 109, 115, 120, 123, 125, 127, 129, 132, 135, 136, 137,139, 141, 145, 148, 151, 155, 159];
$percentiles = [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95];
// get the last element from percentile_bounds which is less than total_score
$value = end(array_filter($percentile_bounds, function ($x) use ($total_score) { return $x < $total_score; }));
// find its index
$key = array_search($value, $percentile_bounds);
// find the corresponding value in percentiles
echo "percentile: $percentiles[$key]";
// 15
Is there a better way of selecting the element from one array (percentiles) based on a position of an element (total_score) in the other array (percentile_bounds)?
Thanks
Note: it is not a duplicate of this.
Clarification: For total_score<=84 the result should be 0 (based on how percentiles work) but it also should not happen. In the code above I do not deal with this condition so it's ok not to but if the solution does, the better :). Thanks #jspit for pointing it out!
You can do it with this line where array_keys gives us an array of keys of our filtered array. end and max do the same job in this case because we have a sorted array and want to return its last index. So finally $percentiles[$lastIndexKeyOfOurFilteredArray] is what we print out:
echo $percentiles[max(array_keys(array_filter($percentile_bounds,function ($x) use ($total_score){return $x<$total_score; })))]
foreach would be more readable and performant approach compared to array_filter
$total_score = 153;
$percentile_bounds = [84, 104, 109, 115, 120, 123, 125, 127, 129, 132, 135, 136, 137, 139, 141, 145, 148, 151, 155, 159];
$percentiles = [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95];
foreach ($percentile_bounds as $key => $bound) {
if ($bound >= $total_score) {
echo 'percentile: ' . $percentiles[max(0, $key - 1)];
break;
}
}
Related
So, I decided to write a perlin noise implementation in php. Don't ask me why, I've forgotten. Following this: https://flafla2.github.io/2014/08/09/perlinnoise.html , I have gotten to the point where I should be getting some results. Octaves haven't been worked in yet, but the vectors should be doing their thing.
Offending code at the bottom of the post.
I had a few mistakes when implementing it as a class (seriously, whose idea was it to make it compulsory to preface every in-class variable with a $this->? It almost gave me a literal headache fixing all the mistakes I'd made), but I think I have caught them all. I did have some trouble doubling my permutation matrix, but that is done as well. I know this because I have printed it. However, when I try to get the hash thing, I get a page-full of PHP Notice: Undefined offset: 1 in perlin.php (0 as well as 1).
This leads to a bunch of variables that should be integers being null. I have tol my functions what to expect, so I get PHP Fatal error: Uncaught TypeError: Argument 1 passed to perlin::grad() must be of the type int, null given, called in perlin.php on line 56 and defined in perlin.php:73
The thing that confuses me the most is that the array that is complaining is defined all the way from 0 to 511 (inclusive).
Am I missing some vital information, like the difference between an index and an offset?
Code:
<?php
class perlin{
public function __construct(){
$p=array_merge($this->permutation,$this->permutation);
print_r($p);
}
private $permutation=array(111, 176, 195, 194, 99, 88, 206, 7, 84, 2, 246, 181, 221, 69, 249, 3, 47, 223, 154, 26, 65, 142, 178, 100, 128, 134, 254, 94, 78, 204, 59, 98, 48, 171, 80, 125, 190, 86, 225, 138, 57, 144, 16, 143, 169, 162, 139, 252, 147, 182, 67, 179, 220, 160, 81, 96, 132, 82, 148, 72, 64, 242, 255, 137, 74, 185, 212, 19, 218, 256, 101, 130, 39, 234, 41, 115, 228, 230, 214, 45, 107, 251, 117, 91, 68, 49, 37, 208, 207, 192, 168, 232, 133, 23, 54, 106, 153, 247, 87, 200, 34, 187, 25, 124, 17, 114, 245, 248, 157, 77, 9, 219, 120, 236, 183, 79, 50, 42, 250, 189, 102, 227, 243, 83, 159, 62, 156, 151, 75, 13, 177, 158, 253, 196, 166, 103, 118, 32, 229, 235, 170, 15, 108, 58, 21, 73, 31, 70, 89, 203, 46, 205, 110, 150, 113, 43, 199, 29, 193, 40, 1, 60, 152, 6, 104, 129, 175, 36, 8, 222, 135, 85, 198, 123, 149, 238, 231, 164, 63, 76, 38, 20, 184, 188, 4, 12, 119, 14, 240, 105, 30, 210, 27, 241, 224, 239, 10, 66, 116, 167, 56, 140, 95, 126, 217, 92, 51, 55, 213, 155, 201, 161, 244, 197, 180, 71, 44, 215, 172, 18, 165, 35, 131, 186, 202, 22, 24, 121, 226, 33, 93, 163, 211, 191, 61, 53, 28, 136, 216, 122, 237, 173, 112, 209, 97, 145, 233, 146, 174, 141, 5, 52, 11, 109, 127, 90);
//generated by seq 1 256|shuf|sed 's/$/,/g'|tr '\n' ' '
public $repeat=0;
private $p=array();
private function inc($num){
$num++;
if($this->repeat>0){
$num%=$this->repeat;
}
return $num;
}
private function fade(float $t){
return $t*$t*$t*($t*($t*6+15)+10);
}
public function perlin(float $x,float $y,float $z){
if($this->repeat>0){
$x=$x%$this->repeat;
$y=$y%$this->repeat;
$z=$z%$this->repeat;
}
$xi=(int)($x) & 255;
$yi=(int)($y) & 255;
$zi=(int)($z) & 255;
$xf=$x-(int)($x);
$yf=$y-(int)($y);
$zf=$z-(int)($z);
echo "$xi $yi $zi $xf $yf $zf<br>\n\n";
$u=$this->fade($xf);
$v=$this->fade($yf);
$w=$this->fade($zf);
$aaa=$this->p[$this->p[$this->p[ $xi ]+ $yi ]+ $zi ];
$aba=$this->p[$this->p[$this->p[ $xi ]+$this->inc($yi)]+ $zi ];
$aab=$this->p[$this->p[$this->p[ $xi ]+ $yi ]+$this->inc($zi)];
$abb=$this->p[$this->p[$this->p[ $xi ]+$this->inc($yi)]+$this->inc($zi)];
$baa=$this->p[$this->p[$this->p[$this->inc($xi)]+ $yi ]+ $zi ];
$bba=$this->p[$this->p[$this->p[$this->inc($xi)]+$this->inc($yi)]+ $zi ];
$bab=$this->p[$this->p[$this->p[$this->inc($xi)]+ $yi ]+$this->inc($zi)];
$bbb=$this->p[$this->p[$this->p[$this->inc($xi)]+$this->inc($yi)]+$this->inc($zi)];
$x1=$this->lerp($this->grad($aaa,$xf,$yf,$zf),
$this->grad($baa,$xf-1,$yf,$zf),$u);
$x2=$this->lerp($this->grad($aba,$xf,$yf-1,$zf),
$this->grad($bba,$xf-1,$yf-1,$zf),$u);
$y1=$this->lerp($x1,$x2,v);
$x1=$this->lerp($this->grad($aab,$xf,$yf,$zf-1),
$this->grad($bab,$xf-1,$yf,$zf-1),$u);
$x2=$this->lerp($this->grad($abb,$xf,$yf-1,$zf-1),
$this->grad($bbb,$xf-1,$yf-1,$zf-1),$u);
$y2=$this->lerp($x1,$x2,v);
return ($this->lerp($y1,$y2,w)+1)/2;
}
private function grad(int $hash,float $x,float $y,float $z){
switch($hash & 0xF){
case 0x0: return $x+$y;
case 0x1: return -$x + $y;
case 0x2: return $x - $y;
case 0x3: return -$x - $y;
case 0x4: return $x + $z;
case 0x5: return -$x + $z;
case 0x6: return $x - $z;
case 0x7: return -$x - $z;
case 0x8: return $y + $z;
case 0x9: return -$y + $z;
case 0xA: return $y - $z;
case 0xB: return -$y - $z;
case 0xC: return $y + $x;
case 0xD: return -$y + $z;
case 0xE: return $y - $x;
case 0xF: return -$y - $z;
default: return 0;
}
}
private function lerp(float $a,float $b,float $x){
return $a+$x*($b-$a);
}
}
?>
I'm doing my homework and I can't find the solution to displaying more than one result in array after doing min and max syntax
my teacher said that I should use min and max to show more than 1 result
$temperatures = [78, 60, 62, 68, 71, 68, 73, 85, 66, 64, 76, 63, 75, 76, 73, 68, 62, 73, 72, 65, 74, 62, 62, 65, 64, 68, 73, 75, 79, 73];
$max = max($temperatures);
$min = min($temperatures);
The final result should be:
average of the temperatures : 70.6
the five lowest temperature lists : 60, 62, 63, 63, 64
the five highest temperature lists : 76, 78, 79, 81, 85
My two cents on it:
$temperatures = [78, 60, 62, 68, 71, 68, 73, 85, 66, 64, 76, 63, 75, 76, 73, 68, 62, 73, 72, 65, 74, 62, 62, 65, 64, 68, 73, 75, 79, 73];
# simply sum the elements then divide by count
$avg = (array_sum($temperatures) / count($temperatures));
# sort arr low -> high
sort($temperatures);
# make els unique
$temperatures = array_unique($temperatures);
$min = array_slice($temperatures, 0, 5); # get first 5 in array
$max = array_slice($temperatures, -5); # get last 5 in array
echo '<pre>'. print_r($avg, 1) .'</pre>';
echo '<pre>'. print_r($min, 1) .'</pre>';
echo '<pre>'. print_r($max, 1) .'</pre>';
I'm trying to build the following numerical series 1, 1, 2, 3, 4, 5, 5, 6 until 100 ( It is a homework) . I have to do this using php code but I cannot get it , I've read the fibonacci method but the numerical series numbers are different.
<?php
$a=1;
$serie="1";
for ($i=1;$i<=100;$i++)
{
if($i%5==0)
{
$serie=$serie.",$i,$i";
}
else
{
$serie=$serie.",$i";
}
}
print $serie;
?>
As #tim pointed out in the comment, the solution is not printing a sequence from 1 to 100 where only numbers that are MOD 5 = 0 are duplicated. That way you do not get the repetition on 1.
From your homework question (which is not really clear in my opinion) I presume you want something like this:
<?php
for ($i = 0; $i < 100; $i++) {
echo $i+1 . ", ";
if ($i % 4 == 0) {
echo $i+1 . ", ";
}
}
?>
It prints:
1, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9, 10, 11, 12, 13, 13, 14, 15, 16, 17, 17, 18, 19, 20, 21, 21, 22, 23, 24, 25, 25, 26, 27, 28, 29, 29, 30, 31, 32, 33, 33, 34, 35, 36, 37, 37, 38, 39, 40, 41, 41, 42, 43, 44, 45, 45, 46, 47, 48, 49, 49, 50, 51, 52, 53, 53, 54, 55, 56, 57, 57, 58, 59, 60, 61, 61, 62, 63, 64, 65, 65, 66, 67, 68, 69, 69, 70, 71, 72, 73, 73, 74, 75, 76, 77, 77, 78, 79, 80, 81, 81, 82, 83, 84, 85, 85, 86, 87, 88, 89, 89, 90, 91, 92, 93, 93, 94, 95, 96, 97, 97, 98, 99, 100,
The logic is to print the index increased by 1 each iteration, and print it again if the result of the modulus operation index % 4 is equal to 0.
got a problem with converting python to php. I've got the following code in python:
user = "DdrkmK5uFKmaaeNqfqReMADSUJ4sVSLrV2A8Bvs8"
passing = "K9hvwANSBW5tLYzuWptWMByTtzZZKHzm"
sha = hashlib.sha256()
sha.update(user)
sha.update(passing)
sha_A = [ord(x) for x in sha.digest()]
sha_A is the following array:
[231, 13, 239, 136, 20, 198, 76, 121, 67, 163, 251, 153, 114, 13, 65, 203, 41, 37, 64, 168, 43, 69, 81, 103, 235, 161, 15, 58, 82, 57, 217, 178]
I already converted it to php:
$user = "DdrkmK5uFKmaaeNqfqReMADSUJ4sVSLrV2A8Bvs8";
$passing = "K9hvwANSBW5tLYzuWptWMByTtzZZKHzm"
$sha = hash_init("sha256");
$sha = hash_update($sha, $user);
$sha = hash_update($sha, $passing);
$sha_A = [];
$i = 0;
$digest = openssl_digest($sha, "sha256");
$digest = str_split($digest);
foreach ($digest as $x) {
$sha_A[$i] = ord($x);
$i = $i + 1;
}
But the returned array $sha looks like this one:
[101, 51, 98, 48, 99, 52, 52, 50, 57, 56, 102, 99, 49, 99, 49, 52, 57, 97, 102, 98, 102, 52, 99, 56, 57, 57, 54, 102, 98, 57, 50, 52]
Maybe some of you will find my mistake?
I saw few errors in your PHP code.
This is a python snippet:
>>> sha = hashlib.sha256()
>>> sha.update(user)
>>> sha.update(passing)
>>> sha_A = [ord(x) for x in sha.digest()]
[135, 146, 107, 215, 70, 126, 179, 21, 19, 177, 191, 236, 182, 136, 192, 53, 148, 42, 160, 24, 63, 224, 170, 211, 32, 131, 59, 146, 60, 162, 77, 2]
And the PHP version, corrected:
$ctx = hash_init('sha256');
hash_update($ctx, $user);
hash_update($ctx, $passing);
$digest = hash_final($ctx, true);
$sha_A = [];
foreach (str_split($digest) as $x) {
$sha_A[] = ord($x);
}
[135, 146, 107, 215, 70, 126, 179, 21, 19, 177, 191, 236, 182, 136, 192, 53, 148, 42, 160, 24, 63, 224, 170, 211, 32, 131, 59, 146, 60, 162, 77, 2]
In your PHP version, $sha = hash_update($sha, $user); was bad because hash_update returns a boolean. The first argument is called the context and is the result of hash_init, the second one is the data to hash. Finally, you call hash_final with the last parameter (raw_output) to true to get binary data.
Last error, using openssl_digest on the SHA result's was computing the digest of the SHA digest's. Funny, isn't it? :).
I have been trying to figure this out for hours and seems that I'm stuck.
When I want to do in the query below is that I am passing some location IDs to IN operator and I don't want MySQL to return ALL the results (table is too large) but only 5 items of every location ID (if items exist).
I have temporarily put a LIMIT 100 until I get it done with your help.
Here's the query:
$sql = "SELECT SQL_CACHE deals.deal_ID, deals.slug, deals.url, deals.previous_price, deals.title, deals.image, deals.price, deals.end, deals.purchases, deals.date_added,
deals_locations.location_ID, deals.hits
FROM deals
INNER JOIN deals_locations
WHERE deals.status = 'active'
AND deals_locations.deal_ID = deals.deal_ID
AND deals_locations.location_ID IN (".implode(', ', $location_IDs).")
GROUP BY deals.deal_ID
LIMIT 100;";
Thank you very much for your time.
EDIT: Now my query output looks like this:
SELECT SQL_CACHE deals.deal_ID
,deals.slug
,deals.url
,deals.previous_price
,deals.title
,deals.image
,deals.price
,deals.end
,deals.purchases
,deals.date_added
,deals_locations.location_ID
,deals.hits
FROM deals
INNER JOIN deals_locations
WHERE deals.status = 'active'
AND (
SELECT COUNT(*) FROM deals
WHERE deals.deal_ID = deals_locations.deal_ID
) <= 5
AND deals_locations.deal_ID = deals.deal_ID
AND deals_locations.location_ID IN (1, 2, 3, 5, 7, 12, 13, 26, 27, 28, 29, 30, 31, 34, 35, 36, 38, 39, 40, 41, 42, 43, 44, 46, 49, 52, 53, 54, 55, 56, 60, 62, 64, 65, 66, 67, 68, 69, 70, 72, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 89, 90, 97, 107, 10, 21, 32, 33, 37, 51, 4, 6, 8, 9, 11, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 25, 45, 47, 48, 50, 57, 58, 59, 61, 63, 71, 73, 84, 85, 86, 87, 88, 91, 92, 93, 94, 95, 96, 98, 99, 100, 101, 102, 103, 104, 105, 106, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160)
GROUP BY deals.deal_ID;
But still shows more than 5 records for the same location.
EDIT 2: I have tried the UNION ALL approach and seems to be working. Now I get a total result of 30 rows but I am concerned about the size of the query.
Here's what my query looks like now: http://pastebin.com/r6vyG594
The explain is huge so I can't post it online. What should I do to make the query efficient and smaller in size?
It takes about 0.2158 sec to execute.
I can see two ways of doing this:
1 Subquery instead of php implode:
...
AND deals_locations.location_ID IN (SELECT id FROM deals_locations WHERE .... LIMIT 5)
GROUP BY deals.deal_ID
...
EDIT: MySQL does not support limit in subqueries
2 Limit your array when creating/use 5 elements in multidimensional array
implode(', ', $locations_IDs[0]) and so on.
You can also try to make one query/Id
To start with I would add an ON statement with your inner join:
$sql = "SELECT SQL_CACHE deals.deal_ID, deals.slug, deals.url, deals.previous_price, deals.title, deals.image, deals.price, deals.end, deals.purchases, deals.date_added,
deals_locations.location_ID, deals.hits
FROM deals
INNER JOIN deals_locations ON deals_locations.deal_ID = deals.deal_ID AND deals_locations.location_ID IN (".implode(', ', $location_IDs).")
WHERE deals.status = 'active'
GROUP BY deals.deal_ID
LIMIT 100;";
In the above example, I've moved both of your where statements relating to deals_locations to be in the join statement. This will limit how many records are joined from that table...