我有一个小函数可以将数字转换为1000到1k。
<?php
/**
* /Converts a number into a short version, eg: 1000 -1k.
*
* @param int $number The number
* @param int $precision The precision
*
* @return string The formated number
*/
function short_number_format($number, $precision = 1)
{
$lookup = [
1 => '',
1000 => 'K',
1000000 => 'M',
1000000000 => 'B',
1000000000000 => 'T',
];
$result = '';
foreach ($lookup as $boundary => $postfix) {
if ($number < 900 * $boundary) {
$result = number_format($number / $boundary, $precision).$postfix;
break;
}
}
//if we didnt get the result which is most likely to happen
// for larger numbers (rarely) , return the plain number
return $result ?: number_format($number, $precision);
}
一些高级开发人员告诉我,由于循环,代码非常慢。 那是真的吗?
答案 0 :(得分:3)
试试这个:
0.
这样你就可以执行divison 一次而不是乘法每次。
由于分部比乘法花费更多的处理,我们最好将其更改为:
$lookup = [
900 => '',
900000 => 'K',
900000000 => 'M',
900000000000 => 'B',
900000000000000 => 'T',
];
$result = '';
foreach ($lookup as $boundary => $postfix) {
if ($number < $boundary) {
$result = number_format($number / ($boundary/900), $precision) . $postfix;
break;
}
}
理论上,如果从具有大量迭代次数的另一个循环调用short_number_format()函数,理论上这应该更快,并且可以更快地进行操作
答案 1 :(得分:0)
在我看来,这个代码没有任何内容可以引起性能问题。固定长度循环是O(1)操作,几个基本的数学计算根本不是性能问题的根本原因。
我修复了你的后缀中的千兆字节错误,并咨询你的开发人员,看看他/她的关注是否是因为在运行时实际上出现了性能问题。也许你可以提供一些定时器来测量哪些操作使用最多的时间。您还可以创建一个单元测试,以验证您已经直观了解自己的功能表现。
添加:我创建了一个基于字符串的版本,它不使用循环并根据您的版本计时。虽然无循环版本的运行速度可能会稍微快一些,但您会发现现有版本已经可以在相当适中的CPU上每秒处理数十万个请求。对您的功能进行微观优化不太可能产生任何明显的影响。
<!DOCTYPE html>
<html>
<body>
<?php
$t1 = microtime(true);
for ($i=0; $i<100000; $i++) {
scaleV1($i, $i%3 + 1);
}
timesince($t1);
$t2 = microtime(true);
for ($i=0; $i<100000; $i++) {
short_number_format($i, $i%3 + 1);
}
timesince($t2);
function timesince($micro) {
$sec=(microtime(true) - $micro);
echo "<p>" . number_format($sec, 3) . "</p>\n";
}
function scaleV1($number, $precision=1) {
$scale_id=" KMGTP";
$w=strlen(intval($number));
$scale=intval($w/3);
if (($w%3==0) && (substr($number,0,1)!=9)) $scale--;
$postfix=$scale==0 ? '' : $scale_id[$scale];
return number_format(($number / pow(1000,$scale)), $precision) .
$postfix;
}
function short_number_format($number, $precision = 1)
{
$lookup = [
1 => '',
1000 => 'K',
1000000 => 'M',
1000000000 => 'G',
1000000000000 => 'T',
];
$result = '';
foreach ($lookup as $boundary => $postfix) {
if ($number < 900 * $boundary) {
$result = number_format($number / $boundary,
$precision).$postfix;
break;
}
}
return $result ?: number_format($number, $precision);
}
?>
</body>
</html>
答案 2 :(得分:0)
这是没有循环或分支的另一种方式:
function short_number_format($number, $precision = 1)
{
$lookup = [
1 => [1,''],
2 => [1,''],
3 => [1,'']
4 => [1000,'K'],
5 => [1000,'K'],
6 => [1000,'K'],
7 => [1000000,'M'],
8 => [1000000,'M'],
9 => [1000000,'M'],
10 => [1000000000,'B'],
11 => [1000000000,'B'],
12 => [1000000000,'B'],
13 => [1000000000000,'T'],
14 => [1000000000000,'T'],
15 => [1000000000000,'T']
];
$N = floor(log($number, 10) + 1);
$result=$number/$lookup[$N][0];
return number_format ($result,$precision) . $lookup[$N][1];
}
在这个方法中,我们使用位数作为查找数组的索引,并使用0和1分别得到除数和字母。
另一种方法是使用(仅当$ number为double或float包含点时):
$N = strpos(strval($number),".")-1; // only if $number has dot like a double
-EDIT使用字符串函数而不是数学的另一种方法,假设输入数字是带点的双精度(未经测试):
function short_number_format($number,
$precision = 1)
{
$lookup = [
1 => [0,''],
2 => [0,''],
3 => [0,'']
4 => [3,'K'],
5 => [3,'K'],
6 => [3,'K'],
7 => [6,'M'],
8 => [6,'M'],
9 => [6,'M'],
10 => [9,'B'],
11 => [9,'B'],
12 => [9,'B'],
13 => [12,'T'],
14 => [12,'T'],
15 => [12,'T']
];
$sn = strval($number);
$N = strpos($sn,".") - 1;
$pos = $N - $lookup[$N][0];
$sn = str_replace('.', '', $sn) ;
$sn = substr_replace($sn, ".", $pos, 0);
return number_format (doubleval($sn),$precision) . $lookup[$N][1];
}
一般的经验法则是避免在关键循环中依赖数据进行分支
参考:https://stackoverflow.com/a/11227902/6281135
同样来自同一个线程,如果要保留IF语句,排序数据似乎运行得更快。通过数据我的意思是传递给你的函数的数据,以防你从另一个循环调用它。